Files
oceanbase/deps/easy/src/util/easy_util.c

198 lines
4.9 KiB
C

#include <sys/time.h>
#include <math.h>
#include "util/easy_util.h"
#include "io/easy_log.h"
#define STACK_BT_BUFFER_LENGTH 2048
#define MEASUREMENTS 200
#define USECSTEP 10
#define USECSTART 100
static const double EASY_DOUBLE_EPSINON = 1e-14;
extern char *parray_c(char *buf, int64_t len, int64_t *array, int size);
const char *easy_lbt()
{
static __thread void *addrs[100];
static __thread char buf[1024];
int size = ob_backtrace_c(addrs, 100);
return parray_c(buf, sizeof(buf), (int64_t *)addrs, size);
}
const char *easy_lbt_str()
{
static __thread void *addrs[100];
static __thread char buf[STACK_BT_BUFFER_LENGTH];
int size, len, pos = 0;
char **symbols = NULL;
char *sym;
int idx;
sprintf(buf, "\n");
pos++;
size = ob_backtrace_c(addrs, 100);
symbols = backtrace_symbols(addrs, 100);
if (NULL == symbols) {
return buf;
}
for (idx = 0; idx < size; idx++) {
sym = symbols[idx];
if (NULL != sym) {
len = strlen(sym);
if ((pos + len + 1) > STACK_BT_BUFFER_LENGTH) {
break;
} else {
sprintf(buf + pos, "%s\n", sym);
pos += len + 1;
}
}
}
free(symbols);
return buf;
}
const char* easy_get_func_name(void *addr)
{
char *func_name = "";
char **res;
res = backtrace_symbols(&addr, 1);
if (res != NULL) {
func_name = res[0];
free(res);
}
return func_name;
}
/*
* Use linear regression to calculate cycles per microsecond.
*/
static double sample_get_cpu_mhz(void)
{
struct timeval tv1, tv2;
cycles_t start;
double sx = 0, sy = 0, sxx = 0, syy = 0, sxy = 0;
double tx, ty;
int i;
/* Regression: y = a + b x */
long x[MEASUREMENTS];
cycles_t y[MEASUREMENTS];
// double a; /* system call overhead in cycles */
double b; /* cycles per microsecond */
double r_2;
for (i = 0; i < MEASUREMENTS; ++i) {
start = easy_get_cycles();
if (gettimeofday(&tv1, NULL)) {
easy_error_log("gettimeofday failed.\n");
return 0;
}
do {
if (gettimeofday(&tv2, NULL)) {
easy_error_log("gettimeofday failed.\n");
return 0;
}
} while ((tv2.tv_sec - tv1.tv_sec) * 1000000 +
(tv2.tv_usec - tv1.tv_usec) < USECSTART + i * USECSTEP);
x[i] = (tv2.tv_sec - tv1.tv_sec) * 1000000 +
tv2.tv_usec - tv1.tv_usec;
y[i] = easy_get_cycles() - start;
// if (DEBUG_DATA)
// DEBUG("x=%ld y=%Ld.\n", x[i], (long long)y[i]);
}
for (i = 0; i < MEASUREMENTS; ++i) {
tx = x[i];
ty = y[i];
sx += tx;
sy += ty;
sxx += tx * tx;
syy += ty * ty;
sxy += tx * ty;
}
b = (MEASUREMENTS * sxy - sx * sy) / (MEASUREMENTS * sxx - sx * sx);
// a = (sy - b * sx) / MEASUREMENTS;
// DEBUG("a = %g\n", a);
// DEBUG("b = %g\n", b);
// DEBUG("a / b = %g\n", a / b);
r_2 = (MEASUREMENTS * sxy - sx * sy) *
(MEASUREMENTS * sxy - sx * sy) /
(MEASUREMENTS * sxx - sx * sx) /
(MEASUREMENTS * syy - sy * sy);
// DEBUG("r^2 = %g\n", r_2);
if (r_2 < 0.9) {
easy_error_log("Correlation coefficient r^2: %g < 0.9.\n", r_2);
return 0;
}
return b;
}
static double proc_get_cpu_mhz(int no_cpu_freq_fail)
{
FILE *f;
char buf[256];
double mhz = 0.0;
f = fopen("/proc/cpuinfo", "r");
if (!f) {
return 0.0;
}
while (fgets(buf, sizeof(buf), f)) {
double m;
int rc;
rc = sscanf(buf, "cpu MHz : %lf", &m);
if (rc != 1) { /* PPC has a different format */
rc = sscanf(buf, "clock : %lf", &m);
if (rc != 1) {
continue;
}
}
if (fabs(mhz) < EASY_DOUBLE_EPSINON) {
mhz = m;
continue;
}
if (fabs(mhz - m) > EASY_DOUBLE_EPSINON) {
// DEBUG("Conflicting CPU frequency values detected: %lf != %lf.\n", mhz, m);
if (no_cpu_freq_fail) {
// DEBUG("Test integrity may be harmed!\n");
} else {
fclose(f);
return 0.0;
}
continue;
}
}
fclose(f);
return mhz;
}
double easy_get_cpu_mhz(int no_cpu_freq_fail)
{
double sample, proc, delta;
sample = sample_get_cpu_mhz();
proc = proc_get_cpu_mhz(no_cpu_freq_fail);
easy_debug_log("Got CPU mhz, sample(%lf), proc(%lf).\n", sample, proc);
if ((fabs(proc) < EASY_DOUBLE_EPSINON) ||
(fabs(sample) < EASY_DOUBLE_EPSINON)) {
return 0;
}
delta = proc > sample ? proc - sample : sample - proc;
if (delta / proc > 0.01) {
easy_warn_log("Measured timestamp frequency %g differs from nominal %g MHz.\n", sample, proc);
return sample;
}
return proc;
}