8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 14:03:02 +01:00
firebird-mirror/src/jrd/perf.cpp

375 lines
8.0 KiB
C++

/*
* PROGRAM: JRD Access Method
* MODULE: perf.cpp
* DESCRIPTION: Performance monitoring routines
*
* The contents of this file are subject to the Interbase Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy
* of the License at http://www.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "DELTA" port
* 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "IMP" port
*
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
*
*/
#include "firebird.h"
#include <stdio.h>
#include <limits.h>
#include "../common/classes/timestamp.h"
#include "../jrd/common.h"
#include "../jrd/ibase.h"
#include "../jrd/perf.h"
#include "../jrd/gds_proto.h"
#include "../jrd/perf_proto.h"
#include "../jrd/gdsassert.h"
#ifdef HAVE_SYS_TIMES_H
#include <sys/times.h>
#endif
#ifdef HAVE_SYS_TIMEB_H
# include <sys/timeb.h>
#endif
static SLONG get_parameter(const SCHAR**);
#ifndef HAVE_TIMES
static void times(struct tms*);
#endif
static const SCHAR items[] = {
isc_info_reads,
isc_info_writes,
isc_info_fetches,
isc_info_marks,
isc_info_page_size, isc_info_num_buffers,
isc_info_current_memory, isc_info_max_memory
};
static const SCHAR* report =
"elapsed = !e cpu = !u reads = !r writes = !w fetches = !f marks = !m$";
#ifdef VMS
#define TICK 100
extern void ftime();
#endif
#if defined(WIN_NT) && !defined(CLOCKS_PER_SEC)
#define TICK 100
#endif
/* EKU: TICK (sys/param.h) and CLOCKS_PER_SEC (time.h) may both be defined */
#if !defined(TICK) && defined(CLOCKS_PER_SEC)
#define TICK ((SLONG)CLOCKS_PER_SEC)
#endif
#ifndef TICK
#define TICK ((SLONG)CLK_TCK)
#endif
int API_ROUTINE perf_format(
const PERF* before,
const PERF* after,
const SCHAR* string, SCHAR* buffer, SSHORT* buf_len)
{
/**************************************
*
* P E R F _ f o r m a t
*
**************************************
*
* Functional description
* Format a buffer with statistical stuff under control of formatting
* string. Substitute in appropriate stuff. Return the length of the
* formatting output.
*
**************************************/
SCHAR c;
SLONG buffer_length = (buf_len) ? *buf_len : 0;
SCHAR* p = buffer;
while ((c = *string++) && c != '$') {
if (c != '!')
*p++ = c;
else {
SLONG delta;
switch (c = *string++) {
case 'r':
delta = after->perf_reads - before->perf_reads;
break;
case 'w':
delta = after->perf_writes - before->perf_writes;
break;
case 'f':
delta = after->perf_fetches - before->perf_fetches;
break;
case 'm':
delta = after->perf_marks - before->perf_marks;
break;
case 'd':
delta =
after->perf_current_memory - before->perf_current_memory;
break;
case 'p':
delta = after->perf_page_size;
break;
case 'b':
delta = after->perf_buffers;
break;
case 'c':
delta = after->perf_current_memory;
break;
case 'x':
delta = after->perf_max_memory;
break;
case 'e':
delta = after->perf_elapsed - before->perf_elapsed;
break;
case 'u':
delta = after->perf_times.tms_utime -
before->perf_times.tms_utime;
break;
case 's':
delta = after->perf_times.tms_stime -
before->perf_times.tms_stime;
break;
default:
sprintf(p, "?%c?", c);
while (*p)
p++;
}
switch (c) {
case 'r':
case 'w':
case 'f':
case 'm':
case 'd':
case 'p':
case 'b':
case 'c':
case 'x':
sprintf(p, "%"SLONGFORMAT, delta);
while (*p)
p++;
break;
case 'u':
case 's':
#ifdef VMS
sprintf(p, "%"SLONGFORMAT".%.2"SLONGFORMAT, delta / 100, (delta % 100));
#else
sprintf(p, "%"SLONGFORMAT".%.2"SLONGFORMAT, delta / TICK,
(delta % TICK) * 100 / TICK);
#endif
while (*p)
p++;
break;
case 'e':
sprintf(p, "%"SLONGFORMAT".%.2"SLONGFORMAT, delta / 100, delta % 100);
while (*p)
p++;
break;
}
}
}
*p = 0;
const int length = p - buffer;
if (buffer_length && (buffer_length -= length) >= 0) {
memset(p, ' ', buffer_length);
}
return length;
}
void API_ROUTINE perf_get_info(FB_API_HANDLE* handle, PERF* perf)
{
/**************************************
*
* P E R F _ g e t _ i n f o
*
**************************************
*
* Functional description
* Acquire timing and performance information. Some info comes
* from the system and some from the database.
*
**************************************/
SSHORT buffer_length, item_length;
ISC_STATUS_ARRAY jrd_status;
#ifdef HAVE_GETTIMEOFDAY
struct timeval tp;
#else
struct timeb time_buffer;
#define LARGE_NUMBER 696600000 /* to avoid overflow, get rid of decades) */
#endif
/* If there isn't a database, zero everything out */
if (!*handle) {
memset(perf, 0, sizeof(PERF));
}
/* Get system times */
times(&perf->perf_times);
#ifdef HAVE_GETTIMEOFDAY
GETTIMEOFDAY(&tp);
perf->perf_elapsed = tp.tv_sec * 100 + tp.tv_usec / 10000;
#else
ftime(&time_buffer);
perf->perf_elapsed =
(time_buffer.time - LARGE_NUMBER) * 100 + (time_buffer.millitm / 10);
#endif
if (!*handle)
return;
SCHAR buffer[256];
buffer_length = sizeof(buffer);
item_length = sizeof(items);
isc_database_info(jrd_status,
handle,
item_length, items, buffer_length, buffer);
const char* p = buffer;
while (true)
switch (*p++) {
case isc_info_reads:
perf->perf_reads = get_parameter(&p);
break;
case isc_info_writes:
perf->perf_writes = get_parameter(&p);
break;
case isc_info_marks:
perf->perf_marks = get_parameter(&p);
break;
case isc_info_fetches:
perf->perf_fetches = get_parameter(&p);
break;
case isc_info_num_buffers:
perf->perf_buffers = get_parameter(&p);
break;
case isc_info_page_size:
perf->perf_page_size = get_parameter(&p);
break;
case isc_info_current_memory:
perf->perf_current_memory = get_parameter(&p);
break;
case isc_info_max_memory:
perf->perf_max_memory = get_parameter(&p);
break;
case isc_info_end:
return;
case isc_info_error:
if (p[2] == isc_info_marks)
perf->perf_marks = 0;
else if (p[2] == isc_info_current_memory)
perf->perf_current_memory = 0;
else if (p[2] == isc_info_max_memory)
perf->perf_max_memory = 0;
{
const SLONG temp = isc_vax_integer(p, 2);
fb_assert(temp <= MAX_SSHORT);
p += temp + 2;
}
perf->perf_marks = 0;
break;
default:
return;
}
}
void API_ROUTINE perf_report(
const PERF* before,
const PERF* after, SCHAR* buffer, SSHORT* buf_len)
{
/**************************************
*
* p e r f _ r e p o r t
*
**************************************
*
* Functional description
* Report a common set of parameters.
*
**************************************/
perf_format(before, after, report, buffer, buf_len);
}
static SLONG get_parameter(const SCHAR** ptr)
{
/**************************************
*
* g e t _ p a r a m e t e r
*
**************************************
*
* Functional description
* Get a parameter (length is encoded), convert to internal form,
* and return.
*
**************************************/
SSHORT l = *(*ptr)++;
l += (*(*ptr)++) << 8;
const SLONG parameter = isc_vax_integer(*ptr, l);
*ptr += l;
return parameter;
}
#ifndef HAVE_TIMES
static void times(struct tms* buffer)
{
/**************************************
*
* t i m e s
*
**************************************
*
* Functional description
* Emulate the good old unix call "times". Only both with user time.
*
**************************************/
buffer->tms_utime = clock();
}
#endif