Skip to content

Instantly share code, notes, and snippets.

@mrbid
Last active October 22, 2022 10:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrbid/31e295c5db2339820dde44571fb98596 to your computer and use it in GitHub Desktop.
Save mrbid/31e295c5db2339820dde44571fb98596 to your computer and use it in GitHub Desktop.
A simple benchmark of FPU math functions using RDTSC + basic precision benching of sqrt().
/*
James William Fletcher (github.com/mrbid)
August 2021
Simple math function benchmark using RDTSC.
https://james-william-fletcher.medium.com/rdtsc-the-only-way-to-benchmark-fc84562ef734
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <locale.h>
#include <sys/time.h>
#include <x86intrin.h>
//////// ALTERNATE RDTSC
static inline uint32_t rdtsc(void)
{
uint32_t a = 0;
asm volatile("rdtsc":"=a"(a)::"edx");
return a;
}
//////// BASIC PRECISION
#include <time.h>
void basic_test(const time_t interval)
{
float r = 0;
unsigned long e = 0;
time_t st = time(0);
while(time(0) - st <= interval)
{
r += sqrt(time(0));
e++;
}
const unsigned long ui = (unsigned int)interval;
printf("Executions in %'lu seconds: %'lu\n", interval, e);
printf("Executions per millisecond: %'lu\n", e/(1000*ui));
printf("Executions per microsecond: %'lu\n", e/(1000000*ui));
printf("~%'.1f executions every nanosecond\n", (float)e/(1000000000*ui));
printf("%c\n", (char)r);
}
// int main()
// {
// basic_test(3);
// return 0;
// }
//////// ADVANCED PRECISION
#include <x86intrin.h>
void advanced_test(const time_t iterations)
{
float r = 0;
uint64_t avg = 0, min = -1, max = 0;
for(int i = 0; i < iterations; i++)
{
const uint64_t st = __rdtsc();
r += sqrt(st);
const uint64_t et = __rdtsc()-st;
avg += et;
if(et > max)
max = et;
if(et < min)
min = et;
}
printf("sqrt() Min Cycles: %'lu\n", min);
printf("sqrt() Max Cycles: %'lu\n", max);
printf("sqrt() Avg Cycles: %'lu\n", avg / iterations);
printf("%c\n", (char)r);
}
// int main()
// {
// advanced_test(3000000);
// return 0;
// }
//////// HIGH PRECISION
#define AVGITER 3000000
static inline float rsqrtss(float f) // this is not a fair comparison to sqrt(double)
{
return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(f)));
}
int main()
{
printf("\nHigh Precision:\n");
setlocale(LC_NUMERIC, "");
float ret = 0;
uint64_t st = 0, et = 0, avg = 0;
// cbrt
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += cbrt(st);
avg += __rdtsc()-st;
}
printf("cbrt() Cycles: %'lu\n", avg / AVGITER);
// exp10
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += exp10(st);
avg += __rdtsc()-st;
}
printf("exp10() Cycles: %'lu\n", avg / AVGITER);
// exp2
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += exp2(st);
avg += __rdtsc()-st;
}
printf("exp2() Cycles: %'lu\n", avg / AVGITER);
// exp
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += exp(st);
avg += __rdtsc()-st;
}
printf("exp() Cycles: %'lu\n", avg / AVGITER);
// hypot
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += hypot(st, st);
avg += __rdtsc()-st;
}
printf("hypot() Cycles: %'lu\n", avg / AVGITER);
// log10
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += log10(st);
avg += __rdtsc()-st;
}
printf("log10() Cycles: %'lu\n", avg / AVGITER);
// log2
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += log2(st);
avg += __rdtsc()-st;
}
printf("log2() Cycles: %'lu\n", avg / AVGITER);
// log
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += log(st);
avg += __rdtsc()-st;
}
printf("log() Cycles: %'lu\n", avg / AVGITER);
// pow
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += pow(st, st);
avg += __rdtsc()-st;
}
printf("pow() Cycles: %'lu\n", avg / AVGITER);
// sqrt
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += sqrt(st);
avg += __rdtsc()-st;
}
printf("sqrt() Cycles: %'lu\n", avg / AVGITER);
// rsqrtss
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += rsqrtss(st);
avg += __rdtsc()-st;
}
printf("rsqrtss() Cycles: %'lu\n", avg / AVGITER);
// acos
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += acos(st);
avg += __rdtsc()-st;
}
printf("acos() Cycles: %'lu\n", avg / AVGITER);
// asin
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += asin(st);
avg += __rdtsc()-st;
}
printf("asin() Cycles: %'lu\n", avg / AVGITER);
// atan
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += atan(st);
avg += __rdtsc()-st;
}
printf("atan() Cycles: %'lu\n", avg / AVGITER);
// atan2
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += atan2(st, st);
avg += __rdtsc()-st;
}
printf("atan2() Cycles: %'lu\n", avg / AVGITER);
// cos
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += cos(st);
avg += __rdtsc()-st;
}
printf("cos() Cycles: %'lu\n", avg / AVGITER);
// tan
avg = 0;
for(int i = 0; i < AVGITER; i++)
{
st = __rdtsc();
ret += tan(st);
avg += __rdtsc()-st;
}
printf("tan() Cycles: %'lu\n", avg / AVGITER);
// perform a basic low precision test
printf("\nBasic Precision sqrt():\n");
basic_test(3);
// perform an advanced precision test
printf("Advanced Precision sqrt():\n");
advanced_test(3000000);
// done
printf("%c\n", (char)ret); // forces the compiler to not disregard the functions we are testing
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment