Files
oceanbase/deps/easy/src/util/easy_util.c
wangzelin.wzl 93a1074b0c patch 4.0
2022-10-24 17:57:12 +08:00

227 lines
5.7 KiB
C

/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#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;
static char *parray(char *buf, int64_t len, int64_t *array, int size)
{
int64_t pos = 0;
int64_t count = 0;
int64_t i = 0;
for (i = 0; i < size; i++) {
count = snprintf(buf + pos, len - pos, "0x%lx ", array[i]);
if (count >= 0 && pos + count + 1 < len) {
pos += count;
} else {
break;
}
}
buf[pos + 1] = 0;
return buf;
}
const char *easy_lbt()
{
static __thread void *addrs[100];
static __thread char buf[1024];
int size = backtrace(addrs, 100);
return parray(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 = backtrace(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;
}