diff options
Diffstat (limited to 'src/statistics.c')
-rwxr-xr-x | src/statistics.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/src/statistics.c b/src/statistics.c new file mode 100755 index 0000000..4af4c22 --- /dev/null +++ b/src/statistics.c @@ -0,0 +1,460 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <sys/time.h> // gettimeofday + +#include <stdio.h> +#include <malloc.h> +#include <string.h> +#include <assert.h> +#include <time.h> + +#include "statistics.h" + +#ifdef STANDALONE +#define EXPORT_API +#endif + +#include <sys/time.h> +#include <sys/utsname.h> +#include <sys/resource.h> +#include <unistd.h> + + +#include <stdarg.h> +#include "statistics.h" + +#define MAX_UINT32 (0xFFFFFFFFL) +#define MAX_UINT64 (0xFFFFFFFFFFFFFFFFLL) + +// defs. +#define MM_TA_MAX_ACCUM 100 + + +typedef struct _mm_ta_accum_item +{ + unsigned long long elapsed_accum; + unsigned long num_calls; + unsigned long long elapsed_min; + unsigned long long elapsed_max; + unsigned long long first_start; + unsigned long long last_end; + + char* name; + + unsigned long long timestamp; + int on_estimate; + int num_unpair; +} mm_ta_accum_item; + + +static void PrintLog(const char *file, int line, const char *msg, ...) +{ + va_list va; + + va_start(va, msg); + fprintf(stderr ,"[STAT] %s:%d:",file, line); + vfprintf(stderr ,msg, va); + fprintf(stderr, "\n"); + va_end(va); +} + +#define MyPrintf(...) PrintLog(__FILE__, __LINE__, ##__VA_ARGS__ ) + + +// internal func. +static void __free_accums(void); +static int __get_accum_index(const char* name); + + +// global var. +static mm_ta_accum_item ** g_accums = NULL; +static int g_accum_index = 0; +static int g_accum_longest_name = 0; +static unsigned long long g_accum_first_time = MAX_UINT64; // jmlee + + +int PERF_INIT(void) +{ + if (g_accums) + { + return 0; + } + + g_accums = (mm_ta_accum_item **) calloc (1, MM_TA_MAX_ACCUM * sizeof(mm_ta_accum_item *) ); + if(!g_accums) + { + assert(0); + return -1; + } + + g_accum_first_time = MAX_UINT64; + + return 0; +} + +int PERF_DEINIT(void) +{ + if ( ! g_accums ) + { + return 0; + } + + __free_accums(); + + g_accum_first_time = MAX_UINT64; + + return 0; +} + + +static int __get_accum_index(const char* name) +{ + int i; + + assert(name); + + // find index + for ( i = 0; i < g_accum_index; i++ ) + { + if ( strcmp( name, g_accums[i]->name ) == 0 ) + return i; + } + + return -1; +} + +static void __free_accums(void) +{ + int i = 0; + + if ( ! g_accums ) + return; + + for ( i = 0; i < g_accum_index; i++ ) + { + if ( g_accums[i] ) + { + if ( g_accums[i]->name ) + free ( g_accums[i]->name ); + + free ( g_accums[i] ); + + g_accums[i] = NULL; + } + } + + g_accum_index = 0; + g_accum_longest_name = 0; + + free ( g_accums ); + g_accums = NULL; +} + + + +int mm_ta_accum_item_begin(const char* name, bool show, const char* filename, int line) +{ + mm_ta_accum_item * accum = NULL; + int index = 0; + int name_len = 0; + struct timeval t; + + if (!g_accums) + return 0; + + if ( g_accum_index == MM_TA_MAX_ACCUM ) + return -1; + + if ( !name ) + return -1; + + name_len = strlen(name); + if( name_len == 0 ) + return -1; + + // if 'name' is new one. create new item. + if ( (index = __get_accum_index(name)) == -1 ) + { + accum = ( mm_ta_accum_item * ) calloc(1, sizeof( mm_ta_accum_item ) ); + if ( !accum ) + { + assert(0); + return -1; + } + + // clear first. + memset( accum, 0, sizeof (mm_ta_accum_item) ); + accum->elapsed_min = MAX_UINT64; + + accum->name = strdup(name); + // add it to list. + g_accums[g_accum_index] = accum; + g_accum_index++; + + if ( g_accum_longest_name < name_len ) + g_accum_longest_name = name_len; + + } + else + { + accum = g_accums[index]; + } + + // verify pairs of begin, end. + if (accum->on_estimate) + { + MyPrintf("[%s] is not 'end'ed!\n", accum->name); + accum->num_unpair ++; + return -1; + } + + accum->on_estimate = 1; + + // get timestamp + gettimeofday( &t, NULL ); + accum->timestamp = t.tv_sec * 1000000UL + t.tv_usec; + + if ( accum->first_start == 0 ) + { // assum that timestamp never could be zero. + accum->first_start = accum->timestamp; + + if ( g_accum_first_time > accum->first_start ) + { + g_accum_first_time = accum->first_start ; + } + } + + if ( show ) + MyPrintf("[ACCUM BEGIN] %s : %ld ---(%s:%d)\n", name, accum->timestamp, filename, line ); + + accum->num_calls++; + + return 0; +} + +int mm_ta_accum_item_end(const char* name, bool show, const char* filename, int line) +{ + mm_ta_accum_item * accum = NULL; + unsigned long long tval = 0LL; + int index = 0; + struct timeval t; + + if (!g_accums) + return 0; + + if ( g_accum_index == MM_TA_MAX_ACCUM ) + return -1; + + if ( !name ) + return -1; + + if( strlen ( name ) == 0 ) + return -1; + + // varify the 'name' is already exist. + if ( (index = __get_accum_index(name)) == -1 ) + { + MyPrintf("[%s] is not added before!\n", name); + return -1; + } + + accum = g_accums[index]; + + // verify pairs of begin, end. + if (!accum->on_estimate) + { + MyPrintf("[%s] is not 'begin' yet!\n", accum->name); + accum->num_unpair ++; + return -1; + } + + // get time first for more accuracy. + gettimeofday( &t, NULL ); + tval = t.tv_sec*1000000UL + t.tv_usec; + + // update last_end + accum->last_end = tval; + +#if 0 + if ( accum->first_start > accum->last_end ) + { + MyPrintf("Invalied timestamp:%s. Start:%lu End=%lu\n", accum->name, accum->first_start , accum->last_end); + } +#endif + + // make get elapsed time. + tval = tval - accum->timestamp; + + // update min/max + accum->elapsed_max = tval > accum->elapsed_max ? tval : accum->elapsed_max; + accum->elapsed_min = tval < accum->elapsed_min ? tval : accum->elapsed_min; + + if ( show ) + MyPrintf("[ACCUM END] %s : %llu + %llu ---(%s:%d)\n", name, accum->elapsed_accum, tval, filename, line ); + + // add elapsed time + accum->elapsed_accum = accum->elapsed_accum + tval; + accum->on_estimate = 0; + + return 0; +} + +void __print_some_info(FILE* fp) +{ + if (!fp) + return; + + // General infomation + { + time_t t_val; + char hostname[256] = {'\0',}; +#ifdef LINUX + struct utsname uts; + struct rusage r_usage; +#endif + fprintf(fp, "\n[[ General info ]]\n"); + + // time and date + time(&t_val); + fprintf(fp, "Date : %s", ctime(&t_val) ); + + // system + if ( gethostname(hostname, 255) == 0 ) + { + fprintf(fp, "Hostname : %s\n", hostname); + } +#ifdef LINUX + if ( uname(&uts) >= 0 ) + { + fprintf(fp, "System : %s\n", uts.sysname); + fprintf(fp, "Machine : %s\n", uts.machine); + fprintf(fp, "Nodename : %s\n", uts.nodename); + fprintf(fp, "Release : %s \n", uts.release); + fprintf(fp, "Version : %s \n", uts.version); + } + + // process info. + fprintf(fp, "Process priority : %d\n", getpriority(PRIO_PROCESS, getpid()) ); + + getrusage(RUSAGE_SELF, &r_usage); + fprintf(fp, "CPU usage : User = %ld.%06ld, System = %ld.%06ld\n", + r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec, + r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec ); +#endif + + } + + // host environment variables + { + extern char** environ; + char** env = environ; + + fprintf(fp, "\n[[ Host environment variables ]]\n"); + while(*env) + { + fprintf(fp, "%s\n", *env); + env++; + } + } + + fprintf(fp, "g_accum_first_time = %llu\n", g_accum_first_time); + + fprintf(fp, "\n\n"); + +} + + +void mm_ta_accum_show_result_fp(FILE *fp) +{ + int i = 0; + char format[256]; + +// __print_some_info(fp); + + + fprintf(fp, "============================ BEGIN RESULT ACCUM (usec) ====================\n"); + + snprintf(format, (size_t)sizeof(format), "[Idx] %%-%ds %%10s %%6s %%10s %%10s %%10s %%4s \n", g_accum_longest_name); + + fprintf(fp, format, "Name", "avg", "hit", "total", "min", "max", "pair"); + + snprintf(format, (size_t)sizeof(format), "[%%3d] %%-%ds %%10llu %%6lu %%10llu %%10llu %%10llu %%4s \n", g_accum_longest_name); + + for ( i = 0; i < g_accum_index; i++ ) + { + // prevent 'devide by zero' error + if (g_accums[i]->num_calls == 0) + g_accums[i]->num_calls = 1; + + fprintf(fp, + format, + i, + g_accums[i]->name, + (g_accums[i]->elapsed_accum == 0)?0:(g_accums[i]->elapsed_accum / g_accums[i]->num_calls), // Fix it! : devide by zero. + g_accums[i]->num_calls, + g_accums[i]->elapsed_accum, + g_accums[i]->elapsed_min, + g_accums[i]->elapsed_max, + g_accums[i]->num_unpair == 1 ? "F" : "T" ); + } + + fprintf(fp, "============================ END RESULT ACCUM ============================\n"); + + if ( fp != stdout && fp != stderr ) + { + fclose(fp); + } +} + + +#define _CONSTRUCTOR __attribute__ ((constructor)) +#define _DESTRUCTOR __attribute__ ((destructor)) + +static void _CONSTRUCTOR _DLLInit(void) +{ + PERF_INIT(); +} + +static void _DESTRUCTOR _DLLExit(void) +{ + PERF_DEINIT(); + +} + + +#ifdef STANDALONE +int main(int argc, char* argv[]) +{ + int a = 0, b = 0; + + + PERF_CHECK_BEGIN("Test 1"); + + for ( a = 0 ; a < 10; a++) + { + printf("AAA=%d\n", a); + usleep(1*10E6); + } + + PERF_CHECK_END("Test 1"); + + printf("Test 111\n"); + return 0; +} +#endif + + + |