Skip to content

Commit 259b724

Browse files
authored
Enh: trace in-driver execution time. Extended logging buffer (#171)
* Enh: trace in-driver execution time; ext log buff. This commit adds the possibility to account for the time the execution spends within the driver. For that, it simply adds up the ticks accounted between entering and exiting any ODBC API call. With it, now one can estimate roughly how much time the driver code runs, as well as how long the driver waits for the REST calls. This time accounting is done globally and possibly across multiple threads. Its mostly useful with single-threaded use, though. The commit also adds the possibility to use a much larger logging "extended" buffer. This is useful in troubleshooting cases where larger logging meesages are required (such as when an entire server REST reply is JSON object is needed). Both of these features are disabled by default (for all build types). * addressing PR review note explicitly init global var
1 parent c7aa95b commit 259b724

File tree

5 files changed

+137
-52
lines changed

5 files changed

+137
-52
lines changed

CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,11 @@ if (${WIN32})
135135
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /DTEST_API=")
136136
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_RELEASE} /DTEST_API=")
137137

138-
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /DNDEBUG")
138+
# Only used when a long logging message is required for troubleshooting
139+
# (like one entire server answer).
140+
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /DWITH_EXTENDED_BUFF_LOG")
141+
# Account for the time the process spends within the driver.
142+
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /DWITH_OAPI_TIMING")
139143
else (${WIN32})
140144
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
141145
endif (${WIN32})

driver/log.c

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@
3131
/* global file log */
3232
esodbc_filelog_st *_gf_log = NULL;
3333

34+
#ifdef WITH_EXTENDED_BUFF_LOG
35+
#define ESODBC_EXT_LOG_BUF_SIZE (ESODBC_LOG_BUF_SIZE * 1024)
36+
static char **log_buffs = NULL;
37+
static size_t log_buffs_cnt = 0;
38+
static esodbc_mutex_lt log_buffs_mux = ESODBC_MUX_SINIT;
39+
#endif /* WITH_EXTENDED_BUFF_LOG */
40+
3441
BOOL log_init()
3542
{
3643
int cnt;
@@ -94,6 +101,19 @@ BOOL log_init()
94101

95102
void log_cleanup()
96103
{
104+
# ifdef WITH_EXTENDED_BUFF_LOG
105+
size_t i;
106+
107+
if (log_buffs) {
108+
for (i = 0; i < log_buffs_cnt; i ++) {
109+
free(log_buffs[i]);
110+
}
111+
free(log_buffs);
112+
log_buffs = NULL;
113+
log_buffs_cnt = 0;
114+
}
115+
# endif /* WITH_EXTENDED_BUFF_LOG */
116+
97117
if (_gf_log) {
98118
filelog_del(_gf_log);
99119
_gf_log = NULL;
@@ -305,18 +325,45 @@ static inline void filelog_log(esodbc_filelog_st *log,
305325
time_t now = time(NULL);
306326
int ret;
307327
size_t pos;
328+
# ifndef WITH_EXTENDED_BUFF_LOG
308329
char buff[ESODBC_LOG_BUF_SIZE];
330+
const size_t buff_sz = ESODBC_LOG_BUF_SIZE;
331+
# else /* !WITH_EXTENDED_BUFF_LOG */
332+
static thread_local char *buff = NULL;
333+
const size_t buff_sz = ESODBC_EXT_LOG_BUF_SIZE;
334+
char **r;
335+
# endif /* !WITH_EXTENDED_BUFF_LOG */
309336
char ebuff[LOG_ERRNO_BUF_SIZE];
310337
const char *sfile, *next;
311338
/* keep in sync with esodbc_log_levels */
312339
static const char *level2str[] = { "ERROR", "WARN", "INFO", "DEBUG", };
313340
assert(level < sizeof(level2str)/sizeof(level2str[0]));
314341

315-
if (ctime_s(buff, sizeof(buff), &now)) {
342+
/* if extended logging is needed (such as when needing an entire server
343+
* answer), the (too large for the stack) log printing buffer needs to be
344+
* allocate on heap and tracked to be freed on lib process detach */
345+
# ifdef WITH_EXTENDED_BUFF_LOG
346+
if (! buff) {
347+
if (! (buff = malloc(buff_sz))) {
348+
return;
349+
}
350+
ESODBC_MUX_LOCK(&log_buffs_mux);
351+
if (! (r = realloc(log_buffs, (log_buffs_cnt + 1) * sizeof(char *)))) {
352+
free(buff);
353+
buff = NULL;
354+
return;
355+
}
356+
log_buffs = r;
357+
log_buffs[log_buffs_cnt ++] = buff;
358+
ESODBC_MUX_UNLOCK(&log_buffs_mux);
359+
}
360+
# endif /* WITH_EXTENDED_BUFF_LOG */
361+
362+
if (ctime_s(buff, buff_sz, &now)) {
316363
/* writing failed */
317364
pos = 0;
318365
} else {
319-
pos = strnlen(buff, sizeof(buff)) - /*\n*/1;
366+
pos = strnlen(buff, buff_sz) - /*\n*/1;
320367
/*
321368
* https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/ctime-s-ctime32-s-ctime64-s-wctime-s-wctime32-s-wctime64-s :
322369
* """
@@ -334,7 +381,7 @@ static inline void filelog_log(esodbc_filelog_st *log,
334381
}
335382

336383
/* write the debugging prefix */
337-
if ((ret = snprintf(buff + pos, sizeof(buff) - pos, " - [%s] %s()@%s:%d ",
384+
if ((ret = snprintf(buff + pos, buff_sz - pos, " - [%s] %s()@%s:%d ",
338385
level2str[level], func, sfile, lineno)) < 0) {
339386
return;
340387
} else {
@@ -343,7 +390,7 @@ static inline void filelog_log(esodbc_filelog_st *log,
343390

344391
/* write the error number details */
345392
if (werrno) {
346-
ret = snprintf(buff + pos, sizeof(buff) - pos, "(%d:", errno);
393+
ret = snprintf(buff + pos, buff_sz - pos, "(%d:", errno);
347394
if (ret < 0) {
348395
return;
349396
} else {
@@ -353,7 +400,7 @@ static inline void filelog_log(esodbc_filelog_st *log,
353400
if (strerror_s(ebuff, sizeof(ebuff), errno)) {
354401
return;
355402
}
356-
ret = snprintf(buff + pos, sizeof(buff) - pos, "%s) ", ebuff);
403+
ret = snprintf(buff + pos, buff_sz - pos, "%s) ", ebuff);
357404
if (ret < 0) {
358405
return;
359406
} else {
@@ -362,22 +409,22 @@ static inline void filelog_log(esodbc_filelog_st *log,
362409
}
363410

364411
/* write user's message */
365-
ret = vsnprintf(buff + pos, sizeof(buff) - pos, fmt, args);
412+
ret = vsnprintf(buff + pos, buff_sz - pos, fmt, args);
366413
if (ret < 0) {
367414
return;
368415
} else {
369416
pos += ret;
370417
}
371418

372419
/* if overrunning, correct the pos, to be able to add a \n\0 */
373-
if (sizeof(buff) < pos + /*\n\0*/2) {
374-
pos = sizeof(buff) - 2;
420+
if (buff_sz < pos + /*\n\0*/2) {
421+
pos = buff_sz - 2;
375422
}
376-
ret = snprintf(buff + pos, sizeof(buff) - pos, "\n");
423+
ret = snprintf(buff + pos, buff_sz - pos, "\n");
377424
if (0 <= ret) {
378425
pos += ret;
379426
}
380-
assert(pos <= sizeof(buff));
427+
assert(pos <= buff_sz);
381428

382429
ESODBC_MUX_LOCK(&log->mux);
383430
filelog_write(log, buff, pos);

driver/odbc.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,16 @@
2424
RET_HDIAGS(hnd, SQL_STATE_HYC00); \
2525
} while (0)
2626

27+
#ifdef WITH_OAPI_TIMING
28+
volatile LONG64 api_ticks = 0;
29+
clock_t thread_local in_ticks = 0;
30+
#endif /* WITH_API_TIMING */
2731

2832
static BOOL driver_init()
2933
{
3034
if (! log_init()) {
3135
return FALSE;
3236
}
33-
INFO("initializing driver.");
34-
if (! queries_init()) {
35-
return FALSE;
36-
}
37-
convert_init();
38-
if (! connect_init()) {
39-
return FALSE;
40-
}
4137
#ifndef NDEBUG
4238
if (_gf_log) {
4339
ERR("leak reporting: on."); /* force create the log handle */
@@ -49,6 +45,14 @@ static BOOL driver_init()
4945
_CrtSetReportFile(_CRT_ASSERT, _gf_log->handle);
5046
}
5147
#endif /* !NDEBUG */
48+
INFO("initializing driver.");
49+
if (! queries_init()) {
50+
return FALSE;
51+
}
52+
convert_init();
53+
if (! connect_init()) {
54+
return FALSE;
55+
}
5256
return TRUE;
5357
}
5458

@@ -96,6 +100,10 @@ BOOL WINAPI DllMain(
96100
ERR("leaks dumped: %d.", _CrtDumpMemoryLeaks());
97101
}
98102
#endif /* !NDEBUG */
103+
#ifdef WITH_OAPI_TIMING
104+
INFO("total in-driver time (secs): %.3f.",
105+
(float)api_ticks / CLOCKS_PER_SEC);
106+
#endif /* WITH_OAPI_TIMING */
99107
INFO("process %u detaching.", GetCurrentProcessId());
100108
log_cleanup();
101109
break;

0 commit comments

Comments
 (0)