Remove obsolete platforms ifdefs from PAL (#8971)
[platform/upstream/coreclr.git] / src / pal / src / misc / perftrace.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*++
6
7
8
9 Module Name:
10
11     misc/perftrace.c
12
13 Abstract:
14     Implementation of PAL Performance trace utilities.
15
16
17
18 --*/
19
20 /* PAL headers */
21
22
23
24 #ifdef PAL_PERF
25
26 #ifndef PLATFORM_UNIX
27 /* PAL Headers */
28 #include "perftrace.h"
29
30 /* Standard Headers */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35
36 #define snprintf _snprintf
37 #define MiscGetenv getenv
38 #define pthread_getspecific TlsGetValue
39 #define THREADSilentGetCurrentThreadId GetCurrentThreadId
40 #define getpid GetCurrentProcessId 
41 #define PAL_fgets fgets // on Windows, we want fgets.
42 #define PAL_fwrite fwrite // on Windows, we want fwrite.
43 #define PAL_fseek fseek // on Windows, we want fseek.
44
45 #else
46 /* PAL Headers */
47 #include "pal/palinternal.h"
48 #include "pal/perftrace.h"
49 #include "pal/dbgmsg.h"
50 #include "pal/cruntime.h"
51 #include "pal/misc.h"
52
53 /* Standard headers */
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <errno.h>
58 #include <pthread.h> /* for pthread_self */
59 #include <dirent.h>
60 #include <unistd.h>
61
62 SET_DEFAULT_DEBUG_CHANNEL(MISC);
63 #endif  //End of PLATFORM_UNIX
64
65
66 #define PAL_PERF_MAX_LOGLINE     0x400  /* 1K */ 
67 #define PAL_PERF_MAX_INPUT       0x1000 /* 4k for single line of input file */
68 #define PAL_PERF_MAX_FUNCTION_NAME 128 /* any one want a function name longer than 127 bytes? */
69 #define PAL_PERF_PROFILE_BUFFER_SIZE 0x400000  /* 4M    */
70 #define PAL_PERF_BUFFER_FULL  (PAL_PERF_PROFILE_BUFFER_SIZE - PAL_PERF_MAX_LOGLINE ) /* (Buffer size - 1K) */
71
72 typedef struct _pal_perf_api_info
73 {
74     ULONGLONG       entries;        /* number of PERF_ENTRY calls for an API function */
75     ULONGLONG       counter;        /* number of PERF_EXIT calls for an API function */
76     ULONGLONG       min_duration;   /* Minimum duration in CPU clock ticks in an API function */ 
77     ULONGLONG       max_duration;   /* Maximum duration in CPU clock ticks in an API function */
78     ULONGLONG       sum_duration;   /* Sum of duration*/
79     double          sum_of_square_duration; /* Sum of square of durations */
80     DWORD           *histograms;    /* An array to store the histogram of an API execution cpu ticks. */
81 } pal_perf_api_info;
82
83
84 typedef struct _pal_perf_thread_info
85 {
86     DWORD               threadId; 
87     pal_perf_api_info * api_table;
88     char *              pal_write_buf;
89     DWORD               buf_offset;
90     BOOL                profile_enabled;
91     ULONGLONG           start_ticks; 
92     ULONGLONG           total_duration; 
93 } pal_perf_thread_info;
94
95 typedef struct _pal_thread_list_node
96 {
97     pal_perf_thread_info * thread_info;  
98     struct _pal_thread_list_node * next;
99
100 } pal_thread_list_node;
101
102 typedef struct _pal_perf_program_info
103 {
104     char    command_line[PAL_PERF_MAX_LOGLINE];
105     char    exe_path[PAL_PERF_MAX_LOGLINE];
106     char    hostname[PAL_PERF_MAX_FUNCTION_NAME];
107     double  cpu_clock_frequency;
108     ULONGLONG start_ticks;
109     ULONGLONG elapsed_time; /* Duration in CPU clock ticks of the program */
110     ULONGLONG total_duration; /* Total CPU clock ticks of all the threads */
111     ULONGLONG pal_duration; /* Total CPU clock ticks spent inside PAL */
112
113 #ifndef PLATFORM_UNIX
114     DWORD   process_id;
115 #else
116     pid_t   process_id;
117 #endif
118     char    start_time[32]; /*  must be at least 26 characters */
119 } pal_perf_program_info;
120
121 #ifndef PLATFORM_UNIX
122 typedef FILE PERF_FILE;
123 #define PERF_FILEFN(x) x
124 #else
125 typedef PAL_FILE PERF_FILE;
126 #define PERF_FILEFN(x) PAL_ ## x
127 #endif
128
129 static ULONGLONG PERFGetTicks();
130 static double PERFComputeStandardDeviation(pal_perf_api_info *api);
131 static void PERFPrintProgramHeaderInfo(PERF_FILE * hFile, BOOL completedExecution);
132 static BOOL PERFInitProgramInfo(LPWSTR command_line, LPWSTR exe_path);
133 static BOOL PERFReadSetting( );
134 static void PERFLogFileName(PathCharString * destFileString, const char *fileName, const char *suffix, int max_length);
135 static void PERFlushAllLogs();
136 static int PERFWriteCounters(pal_perf_api_info * table); 
137 static BOOL PERFFlushLog(pal_perf_thread_info * local_buffer, BOOL output_header);
138 static void PERFUpdateApiInfo(pal_perf_api_info *api, ULONGLONG duration);
139 static char * PERFIsValidPath( const char * path );
140 static char * PERFIsValidFile( const char * path, const char * file);
141
142 typedef char PAL_API_NAME[PAL_PERF_MAX_FUNCTION_NAME];
143
144 static PAL_API_NAME API_list[PAL_API_NUMBER] ;
145 static pal_perf_program_info program_info;
146
147 #ifndef PLATFORM_UNIX
148 static DWORD PERF_tlsTableKey=0 ;
149 #else
150 static pthread_key_t PERF_tlsTableKey=0 ;
151 #endif
152
153 static pal_thread_list_node * process_pal_thread_list=NULL;
154 static BOOL pal_profile_on=FALSE;
155 static BOOL pal_perf_enabled=FALSE;
156 static char * pal_function_map=NULL;
157 static char * perf_default_path=NULL;
158 static char * traced_apis_file=NULL;
159 static char * enabledapis_path=NULL;
160 static char * profile_log_path=NULL;
161 static char * profile_summary_log_name=NULL;
162 static char * profile_time_log_name=NULL;
163 static BOOL summary_only=FALSE;
164 static BOOL nested_tracing=FALSE;
165 static BOOL calibrate=FALSE;
166
167 /* If report_only_called_apis is TRUE,
168    those PAL APIs with no function entry or exit
169    will not be shown in the PAL perf summary file. */
170 static BOOL report_only_called_apis=FALSE;
171
172 /* If the wait_for_startup is TRUE, process profiling
173    will not start until the application
174    has called PAL_EnableProcessProfile(). */
175 static BOOL wait_for_startup=FALSE;
176
177 /* The size of a PAL API execution CPU ticks histogram, i.e.,
178    Number of categories of frequency distrubution of PAL API
179    execution CPU ticks.*/
180 static DWORD pal_perf_histogram_size = 0;
181
182 /* The step size in CPU ticks of each category of the 
183    PAL API execution CPU ticks histogram.*/
184 static DWORD pal_perf_histogram_step = 100;
185
186 static const char PAL_PERF_TRACING[]="PAL_PERF_TRACING";
187 static const char PAL_DEFAULT_PATH[]="PAL_PERF_DEFAULT_PATH";
188 static const char PAL_PERF_TRACEDAPIS_PATH[]="PAL_PERF_TRACEDAPIS_FILE";
189 static const char PAL_PERF_LOG_PATH[]="PAL_PERF_LOG_PATH";
190 static const char PAL_PERF_SUMMARY_LOG_NAME[]="PAL_PERF_SUMMARY_LOG_NAME";
191 static const char PAL_PERF_TIME_LOG_NAME[]="PAL_PERF_TIME_LOG_NAME";
192 static const char PAL_PERF_ENABLED_APIS_PATH[]="PAL_PERF_ENABLEDAPIS_FILE";
193 static const char PAL_SUMMARY_FLAG[]="PAL_PERF_SUMMARY_ONLY";
194 static const char PAL_PERF_NESTED_TRACING[]="PAL_PERF_NESTED_TRACING";
195 static const char PAL_PERF_CALIBRATE[]="PAL_PERF_CALIBRATE";
196 static const char PAL_PERF_REPORT_ONLY_CALLED_APIS[]="PAL_PERF_REPORT_ONLY_CALLED_APIS";
197 static const char PAL_PERF_WAIT_FOR_STARTUP[]="PAL_PERF_WAIT_FOR_STARTUP";
198 static const char PAL_PERF_HISTOGRAM_SIZE[]="PAL_PERF_HISTOGRAM_SIZE";
199 static const char PAL_PERF_HISTOGRAM_STEP[]="PAL_PERF_HISTOGRAM_STEP";
200 static const char traced_apis_filename[]="PerfTracedAPIs.txt";
201 static const char perf_enabled_filename[]="AllPerfEnabledAPIs.txt";
202 #ifndef PLATFORM_UNIX
203 static const char PATH_SEPARATOR[] = "\\";
204 #else
205 static const char PATH_SEPARATOR[] = "/";
206 #endif
207
208
209
210 #ifndef PLATFORM_UNIX
211 #define LLFORMAT "%I64u"
212 #else
213 #define LLFORMAT "%llu"
214 #endif
215
216 static
217 ULONGLONG
218 PERFGetTicks(){
219 #ifdef _X86_ // for BSD and Windows.
220     unsigned long a, d;
221   #ifdef _MSC_VER
222   __asm{
223             rdtsc
224             mov a, eax
225             mov d, edx
226        }
227   #else
228   #undef volatile
229   asm volatile("rdtsc":"=a" (a), "=d" (d));
230   #define volatile DoNotUseVolatileKeyword
231   #endif
232   return ((ULONGLONG)((unsigned int)(d)) << 32) | (unsigned int)(a);
233 #else
234   return 0; // on non-BSD and non-Windows, we'll return 0 for now.
235 #endif // _X86_
236 }
237
238 static
239 double
240 PERFComputeStandardDeviation(pal_perf_api_info *api)
241 {
242     double n;
243     double sum_of_variance;
244     if (api->counter <= 1)
245         return 0.0;
246     n = (double) api->counter;
247     // Calculates standard deviation based on the entire population given as arguments.
248     // Same as stdevp in Excel.
249     sum_of_variance = (n*api->sum_of_square_duration) - (api->sum_duration*api->sum_duration);
250     if (sum_of_variance <= 0.0)
251         return 0.0;
252     return sqrt(sum_of_variance/(n*n));
253 }
254
255
256 static
257 void
258 PERFPrintProgramHeaderInfo(PERF_FILE * hFile, BOOL completedExecution)
259 {
260     ULONGLONG etime = 0;
261     ULONGLONG ttime = 0;
262     ULONGLONG ptime = 0;
263     if (completedExecution) {
264        etime = program_info.elapsed_time;
265        ttime = program_info.total_duration;
266        ptime = program_info.pal_duration;
267     }
268     PERF_FILEFN(fprintf)(hFile,"#LOG\tversion=1.00\n");
269
270     PERF_FILEFN(fprintf)(hFile, "#MACHINE\thostname=%s\tcpu_clock_frequency=%g\n", program_info.hostname,
271         program_info.cpu_clock_frequency);
272     PERF_FILEFN(fprintf)(hFile, "#PROCESS\tprocess_id=%d\ttotal_latency=" LLFORMAT "\tthread_times=" LLFORMAT "\tpal_time=" LLFORMAT "\texe_path=%s\tcommand_line=%s\tstart_time=%s",
273         program_info.process_id, etime, ttime, ptime,
274         program_info.exe_path,program_info.command_line,program_info.start_time);
275 }
276
277 static
278 BOOL
279 PERFInitProgramInfo(LPWSTR command_line, LPWSTR exe_path)
280 {
281     ULONGLONG start_tick;
282 #ifndef PLATFORM_UNIX
283     time_t tv;
284 #else
285     struct timeval tv;
286 #endif
287
288     if (WideCharToMultiByte(CP_ACP, 0, command_line, -1, 
289                         program_info.command_line, PAL_PERF_MAX_LOGLINE-1, NULL, NULL) == 0)
290         return FALSE;
291     if (WideCharToMultiByte(CP_ACP, 0, exe_path, -1, 
292                         program_info.exe_path, PAL_PERF_MAX_LOGLINE-1, NULL, NULL) == 0)
293         return FALSE;
294
295     gethostname(program_info.hostname, PAL_PERF_MAX_FUNCTION_NAME);
296     program_info.process_id = getpid();
297
298 #ifndef PLATFORM_UNIX
299     time( &tv );
300     strcpy(program_info.start_time, ctime( &tv ));
301 #else
302     gettimeofday(&tv, NULL);
303     ctime_r(&tv.tv_sec, program_info.start_time);
304 #endif
305
306     // estimate the cpu clock cycles
307     start_tick = PERFGetTicks();
308     if (start_tick != 0)
309     {
310 #ifndef PLATFORM_UNIX
311         Sleep(1000); //Sleep on Windows takes milliseconds as argument
312 #else
313         sleep(1);
314 #endif
315         program_info.cpu_clock_frequency = (double) (PERFGetTicks() - start_tick);
316     }
317     else
318     {
319         program_info.cpu_clock_frequency = 0.0;
320     }
321
322     program_info.start_ticks = 0;
323     program_info.elapsed_time = 0;
324     program_info.total_duration = 0;
325     program_info.pal_duration = 0;
326
327     return TRUE;
328 }
329
330 static
331 void
332 PERFCalibrationFunction()
333 {
334     PERF_ENTRY(CalibrationFunction);
335     PERF_EXIT(CalibrationFunction);
336 }
337
338 void
339 PERFCalibrate(const char* msg)
340 {
341     ULONGLONG start_tick, cal_ticks;
342     int i=0;
343     int cal_length=100000;
344
345     if (calibrate) {
346        start_tick = PERFGetTicks();
347        for(i=0; i<cal_length; i++)
348        {
349           PERFCalibrationFunction();
350        }
351        cal_ticks = PERFGetTicks() - start_tick;
352        printf("%s: %g\n", msg, (double)(cal_ticks/cal_length));
353     }
354 }
355
356 BOOL
357 PERFInitialize(LPWSTR command_line, LPWSTR exe_path)
358 {
359     BOOL bRead;
360     BOOL ret = TRUE;
361
362     // Check if PAL Perf should be disabled
363     char *pal_perf_tracing_env = MiscGetenv(PAL_PERF_TRACING);
364     if ( pal_perf_tracing_env == NULL || strlen(pal_perf_tracing_env) == 0)
365     {
366         pal_perf_enabled = FALSE;
367         return TRUE;
368     }
369     else
370     {
371         pal_perf_enabled = TRUE;
372     }
373     if (!PERFInitProgramInfo(command_line, exe_path))
374         return FALSE;
375
376     pal_profile_on = FALSE;  // turn it off until we setup everything. 
377     // allocate the TLS index for  structures 
378 #ifndef PLATFORM_UNIX
379     if( ( PERF_tlsTableKey = TlsAlloc() ) == -1 )
380         ret = FALSE;
381 #else
382     if( pthread_key_create(&PERF_tlsTableKey , NULL) != 0 )
383        ret = FALSE;
384 #endif
385
386     if( ret == TRUE )
387     {
388         pal_function_map = (char*)PAL_malloc(PAL_API_NUMBER);
389         if(pal_function_map != NULL)
390         {  
391             bRead = PERFReadSetting( );  // we don't quit even we failed to read the file.
392             ret = TRUE;
393         }
394         /* free the index in TLS */
395         else
396         {
397
398 #ifndef PLATFORM_UNIX
399             TlsFree(PERF_tlsTableKey );
400 #else
401             pthread_key_delete(PERF_tlsTableKey );
402 #endif
403             ret = FALSE;
404         }
405     }
406
407     PERFCalibrate("Overhead when profiling is disabled process-wide");
408
409     return ret;
410 }
411
412
413 void PERFTerminate(  )
414 {
415     static LONG pal_perf_terminated = FALSE;
416
417     if (!pal_perf_enabled || wait_for_startup)
418         return;
419
420     // make sure PERFTerminate is called only once
421     if (InterlockedCompareExchange(&pal_perf_terminated, TRUE, FALSE))
422         return;
423
424     PERFlushAllLogs();
425 #ifndef PLATFORM_UNIX
426     TlsFree(PERF_tlsTableKey );
427 #else
428         pthread_key_delete(PERF_tlsTableKey );
429 #endif
430     PAL_free(pal_function_map);
431 }
432
433
434 BOOL PERFAllocThreadInfo(  )
435 {
436     pal_perf_api_info * apiTable = NULL;
437     pal_thread_list_node * node = NULL;
438     pal_perf_thread_info * local_info = NULL;
439     char * log_buf = NULL;
440     int i;
441     BOOL ret = TRUE;
442
443     if (!pal_perf_enabled)
444         return TRUE;
445
446     /*  The memory allocated per thread for PAL perf tracing is never freed until PAL_Terminate
447         is called in the current implementation. If the test program keeps creating new threads,
448         memory resources could be exhausted. If this ever becomes a problem, the memory allocated
449         per thread should be freed when a thread exits. */
450
451     node = ( pal_thread_list_node * )PAL_malloc(sizeof(pal_thread_list_node));
452     if(node == NULL)
453     {
454         ret = FALSE;
455         goto PERFAllocThreadInfoExit;
456     }
457
458     local_info = (pal_perf_thread_info *)PAL_malloc(sizeof(pal_perf_thread_info)); 
459     if (local_info == NULL)
460     {
461         ret = FALSE;
462         goto PERFAllocThreadInfoExit;
463     }
464
465     apiTable = (pal_perf_api_info *)PAL_malloc( PAL_API_NUMBER *  sizeof(pal_perf_api_info));
466     if (apiTable == NULL)
467     {
468         ret = FALSE;
469         goto PERFAllocThreadInfoExit;
470     }
471
472     node->thread_info = local_info;
473     local_info->api_table=apiTable;
474     local_info->threadId = THREADSilentGetCurrentThreadId();
475
476     for (i = 0; i < PAL_API_NUMBER; i++)
477     {
478         apiTable[i].entries = 0;
479         apiTable[i].counter = 0;
480         apiTable[i].min_duration = _UI64_MAX;
481         apiTable[i].max_duration = 0;
482         apiTable[i].sum_duration = 0;
483         apiTable[i].sum_of_square_duration = 0.0;
484         if (pal_perf_histogram_size > 0)
485         {
486             apiTable[i].histograms = (DWORD *)PAL_malloc(pal_perf_histogram_size*sizeof(DWORD));
487             if (apiTable[i].histograms == NULL)
488             {
489                 ret = FALSE;
490                 goto PERFAllocThreadInfoExit;
491             }
492             memset(apiTable[i].histograms, 0, pal_perf_histogram_size*sizeof(DWORD));
493         }
494         else
495         {
496             apiTable[i].histograms = NULL;
497         }
498     }
499
500     log_buf = (char * )PAL_malloc( PAL_PERF_PROFILE_BUFFER_SIZE );
501
502     if(log_buf == NULL)
503     {
504         ret = FALSE;
505         goto PERFAllocThreadInfoExit;
506     }
507
508     local_info->pal_write_buf=log_buf;
509     local_info->buf_offset = 0;
510     local_info->profile_enabled = FALSE; 
511     local_info->total_duration = 0;
512     local_info->start_ticks = 0;
513     memset(log_buf, 0, PAL_PERF_PROFILE_BUFFER_SIZE);
514
515 #ifndef PLATFORM_UNIX
516     if ( TlsSetValue(PERF_tlsTableKey, local_info) == 0)
517         ret = FALSE;
518 #else
519     if (pthread_setspecific(PERF_tlsTableKey, local_info) != 0)
520        ret = FALSE;
521 #endif
522
523 PERFAllocThreadInfoExit:
524     if (ret == TRUE)
525     {
526         node->next = process_pal_thread_list;
527         process_pal_thread_list = node;
528         PERFFlushLog(local_info, TRUE);
529     }
530     else
531     {
532         if (node != NULL)
533         {
534             PAL_free(node);
535         }
536         if (local_info != NULL)
537         {
538             PAL_free(local_info);
539         }
540         if (apiTable != NULL)
541         {
542             for (i = 0; i < PAL_API_NUMBER; i++)
543             {
544                 if (apiTable[i].histograms != NULL)
545                 {
546                     PAL_free(apiTable[i].histograms);
547                 }
548             }
549             PAL_free(apiTable);
550         }
551         if (log_buf != NULL)
552         {
553             PAL_free(log_buf);
554         }
555     }
556     return ret;
557 }
558
559 static
560 void
561 PERFUpdateProgramInfo(pal_perf_thread_info* local_info)
562 {
563     int i;
564
565     if (!local_info) return;
566
567     // add the elapsed time to the program's total
568     if (local_info->total_duration == 0)
569     {
570         // this thread did not go through PERFDisableThreadProfile code
571         // so compute the total elapsed time for the thread here
572         local_info->total_duration = PERFGetTicks() - local_info->start_ticks;
573     }
574     program_info.total_duration += local_info->total_duration;
575
576     // Add up all the time spent in PAL
577     if (local_info->api_table) {
578        for(i=0; i<PAL_API_NUMBER; i++) {
579          program_info.pal_duration += local_info->api_table[i].sum_duration;
580        }
581     }
582 }
583
584
585 static
586 void
587 PERFlushAllLogs( )
588 {
589     pal_thread_list_node * current, * node;
590     pal_perf_api_info * table1, *table0;
591     int i; 
592     node = process_pal_thread_list;
593     if(node == NULL || node->thread_info == NULL || node->thread_info->api_table == NULL )   // should not come here 
594     {
595         return ;
596     }
597     process_pal_thread_list = process_pal_thread_list->next;
598     table0 = node->thread_info->api_table;
599
600     PERFUpdateProgramInfo(node->thread_info);
601
602     while(process_pal_thread_list)
603     {
604         current=process_pal_thread_list;
605         process_pal_thread_list = process_pal_thread_list->next;
606         if (current->thread_info)
607         {
608             if (current->thread_info->api_table)
609             {
610                 table1 = current->thread_info->api_table;
611                 for(i=0;i<PAL_API_NUMBER;i++)
612                 { 
613                     DWORD j;
614                     if (table1[i].counter == 0)
615                     {
616                         continue;
617                     }
618                     for (j = 0; j < pal_perf_histogram_size; j++)
619                     {
620                         table0[i].histograms[j] += table1[i].histograms[j];
621                     }
622                     table0[i].entries += table1[i].entries;
623                     table0[i].counter += table1[i].counter;
624                     if (table0[i].min_duration > table1[i].min_duration)
625                         table0[i].min_duration = table1[i].min_duration;
626                     if (table0[i].max_duration < table1[i].max_duration)
627                         table0[i].max_duration = table1[i].max_duration;
628                     table0[i].sum_duration += table1[i].sum_duration;
629                     table0[i].sum_of_square_duration += table1[i].sum_of_square_duration;
630                }
631                 PERFUpdateProgramInfo(current->thread_info);
632                 if (table1->histograms != NULL)
633                 {
634                     PAL_free(table1->histograms);
635                 }
636                 PAL_free(table1);
637             }
638             PERFFlushLog(current->thread_info, FALSE);
639             PAL_free(current->thread_info->pal_write_buf);
640             PAL_free(current->thread_info);
641         }
642         PAL_free(current);
643     }
644     PERFWriteCounters(table0);
645     if (table0->histograms != NULL)
646     {
647         PAL_free(table0->histograms);
648     }
649     PAL_free(table0);
650     PERFFlushLog(node->thread_info, FALSE);
651     PAL_free(node->thread_info->pal_write_buf);
652     PAL_free(node->thread_info);
653     PAL_free(node);
654 }
655
656 static
657 void
658 PERFLogFileName(PathCharString& destFileString, const char *fileName, const char *suffix)
659 {
660     const char *dir_path;
661     CPalThread* pThread = InternalGetCurrentThread();
662     dir_path = (profile_log_path == NULL) ? "." : profile_log_path;
663         
664     destFileString.Append(dir_path, strlen(dir_path));
665     destFileString.Append(PATH_SEPARATOR, strlen(PATH_SEPARATOR));
666     if (fileName != NULL)
667     {
668         destFileString.Append(fileName, strlen(fileName));
669     }
670     else
671     {
672         char buffer[33];
673         char* process_id     = itoa(program_info.process_id, buffer, 10);
674         destFileString.Append(process_id, strlen(process_id));
675         destFileString.Append("_", 1);
676         
677         char* current_thread = itoa(THREADSilentGetCurrentThreadId(),buffer, 10);
678         destFileString.Append(current_thread, strlen( current_thread));
679         destFileString.Append(suffix, strlen(suffix));
680     }
681     
682 }
683
684 static
685 int
686 PERFWriteCounters( pal_perf_api_info * table )
687 {
688     PathCharString fileName;
689     pal_perf_api_info * off;
690     PERF_FILE * hFile;
691     int i;
692
693     off = table;
694     
695     PERFLogFileName(fileName, profile_summary_log_name, "_perf_summary.log");
696     hFile = PERF_FILEFN(fopen)(fileName, "a+");
697     if(hFile != NULL)
698     {   
699         PERFPrintProgramHeaderInfo(hFile, TRUE);
700         PERF_FILEFN(fprintf)(hFile,"#api_name\tapi_id\tperf_entries\tperf_exits\tsum_of_latency\tmin_latency\tmax_latency\tstd_dev_latency\tsum_of_square_latency\n");
701         for(i=0;i<PAL_API_NUMBER;i++)
702         {
703             double dev;
704             ULONGLONG min_duration;
705
706             min_duration = (off->min_duration == _UI64_MAX) ? 0 : off->min_duration;
707             if (off->counter >= 1)
708             {
709                 dev = PERFComputeStandardDeviation(off);
710             }
711             else
712             {
713                 dev = 0.0;
714             }
715
716             if (off->counter > 0 || !report_only_called_apis)
717             {
718                 PERF_FILEFN(fprintf)(hFile,"%s\t%d\t" LLFORMAT "\t" LLFORMAT "\t" LLFORMAT "\t" LLFORMAT "\t" LLFORMAT "\t%g\t%g\n",
719                     API_list[i], i, off->entries, off->counter,off->sum_duration,
720                     min_duration, off->max_duration, dev, off->sum_of_square_duration);
721             }
722
723             off++;
724         }
725     }
726     else
727     {
728         return -1;
729     }
730     PERF_FILEFN(fclose)(hFile);
731
732     if (pal_perf_histogram_size > 0)
733     {
734         off = table;
735         PERFLogFileName(fileName, profile_summary_log_name, "_perf_summary.hist");
736         hFile = PERF_FILEFN(fopen)(fileName, "a+");
737
738         if (hFile != NULL)
739         {
740             DWORD j;
741             PERF_FILEFN(fprintf)(hFile,"#api_name\tapi_id");
742             for (j = 0; j < pal_perf_histogram_size; j++)
743             {
744                 PERF_FILEFN(fprintf)(hFile, "\t%d", j*pal_perf_histogram_step);
745             }        
746             PERF_FILEFN(fprintf)(hFile, "\n");
747
748             for(i = 0; i < PAL_API_NUMBER; i++)
749             {
750                 if (off->counter > 0)
751                 {
752                     PERF_FILEFN(fprintf)(hFile,"%s\t%d", API_list[i], i);
753                     
754                     for (j = 0; j < pal_perf_histogram_size; j++)
755                     {
756                         PERF_FILEFN(fprintf)(hFile, "\t%d", off->histograms[j]);
757                     }
758                     
759                     PERF_FILEFN(fprintf)(hFile, "\n");
760                 }
761
762                 off++;
763             }
764         }
765         else
766         {
767             return -1;
768         }
769         PERF_FILEFN(fclose)(hFile);
770     }
771
772     return 0;
773 }
774
775 static
776 BOOL 
777 PERFReadSetting(  )
778 {
779     // this function is not safe right now. 
780     //more code is required to deal with corrupted input file.
781     BOOL ret;
782     unsigned int index;
783     char line[PAL_PERF_MAX_INPUT];
784     char * ptr;
785     char function_name[PAL_PERF_MAX_FUNCTION_NAME];  //no function can be longer than 127 bytes.
786
787     char * file_name_buf;
788     PathCharString file_name_bufPS;
789     char  * input_file_name; 
790     char  * summary_flag_env;
791     char  * nested_tracing_env;
792     char  * calibrate_env;
793     char  * report_only_called_apis_env;
794     char  * wait_for_startup_env;
795     char  * pal_perf_histogram_size_env;
796     char  * pal_perf_histogram_step_env;
797
798 #ifdef PLATFORM_UNIX
799     PAL_FILE * hFile;
800 #else
801     FILE * hFile;
802 #endif
803
804     if((pal_function_map == NULL) || (PAL_API_NUMBER < 0) )
805     {
806         // should not be here.
807     }
808
809     /* do some env setting here */
810     summary_flag_env = MiscGetenv(PAL_SUMMARY_FLAG); 
811     if (summary_flag_env == NULL || strlen(summary_flag_env) == 0) 
812     {
813         summary_only = FALSE;
814     } 
815     else
816     {
817         summary_only = TRUE; 
818     }
819     nested_tracing_env = MiscGetenv(PAL_PERF_NESTED_TRACING); 
820     if (nested_tracing_env == NULL || strlen(nested_tracing_env) == 0) 
821     {
822         nested_tracing = FALSE;
823     } 
824     else
825     {
826         nested_tracing = TRUE; 
827     }
828
829     calibrate_env = MiscGetenv(PAL_PERF_CALIBRATE); 
830     if (calibrate_env == NULL || strlen(calibrate_env) == 0) 
831     {
832         calibrate = FALSE;
833     } 
834     else
835     {
836         calibrate = TRUE; 
837     }
838
839     report_only_called_apis_env = MiscGetenv(PAL_PERF_REPORT_ONLY_CALLED_APIS); 
840     if (report_only_called_apis_env == NULL || strlen(report_only_called_apis_env) == 0) 
841     {
842         report_only_called_apis = FALSE;
843     } 
844     else
845     {
846         report_only_called_apis = TRUE; 
847     }
848
849     wait_for_startup_env = MiscGetenv(PAL_PERF_WAIT_FOR_STARTUP); 
850     if (wait_for_startup_env == NULL || strlen(wait_for_startup_env) == 0) 
851     {
852         wait_for_startup = FALSE;
853     } 
854     else
855     {
856         wait_for_startup = TRUE; 
857     }
858
859     pal_perf_histogram_size_env = MiscGetenv(PAL_PERF_HISTOGRAM_SIZE); 
860     if (pal_perf_histogram_size_env != NULL && strlen(pal_perf_histogram_size_env) > 0) 
861     {
862         long value;
863         char *endptr;
864         value = strtol(pal_perf_histogram_size_env, &endptr, 10);
865         if (value > 0)
866         {
867             pal_perf_histogram_size = (DWORD) value;
868         }
869     }
870
871     pal_perf_histogram_step_env = MiscGetenv(PAL_PERF_HISTOGRAM_STEP); 
872     if (pal_perf_histogram_step_env != NULL && strlen(pal_perf_histogram_step_env) > 0) 
873     {
874         long value;
875         char *endptr;
876         value = strtol(pal_perf_histogram_step_env, &endptr, 10);
877         if (value > 0)
878         {
879             pal_perf_histogram_step = (DWORD) value;
880         }
881     } 
882
883     traced_apis_file = PERFIsValidFile("", MiscGetenv(PAL_PERF_TRACEDAPIS_PATH)); 
884     enabledapis_path = PERFIsValidFile("", MiscGetenv(PAL_PERF_ENABLED_APIS_PATH));
885     profile_log_path = PERFIsValidPath(MiscGetenv(PAL_PERF_LOG_PATH));
886     perf_default_path = PERFIsValidPath( MiscGetenv(PAL_DEFAULT_PATH));
887     profile_summary_log_name = MiscGetenv(PAL_PERF_SUMMARY_LOG_NAME);
888     if (profile_summary_log_name != NULL && strlen(profile_summary_log_name) == 0)
889         profile_summary_log_name = NULL;
890     profile_time_log_name = MiscGetenv(PAL_PERF_TIME_LOG_NAME);
891     if (profile_time_log_name != NULL && strlen(profile_time_log_name) == 0)
892         profile_time_log_name = NULL;
893
894     if( traced_apis_file == NULL)
895     {
896         if(perf_default_path==NULL)
897         { 
898             ret=FALSE;
899             input_file_name = NULL;
900         }
901         else
902         {
903             if( PERFIsValidFile(perf_default_path,traced_apis_filename))
904             {
905                 int length = strlen(perf_default_path) + strlen(PATH_SEPARATOR) + strlen(traced_apis_filename);
906                 file_name_buf = file_name_bufPS.OpenStringBuffer(length);
907                 if ((strcpy_s(file_name_buf, file_name_bufPS.GetSizeOf(), perf_default_path) != SAFECRT_SUCCESS) ||
908                     (strcat_s(file_name_buf, file_name_bufPS.GetSizeOf(), PATH_SEPARATOR) != SAFECRT_SUCCESS) ||
909                     (strcat_s(file_name_buf, file_name_bufPS.GetSizeOf(), traced_apis_filename) != SAFECRT_SUCCESS))
910                 {
911                     file_name_bufPS.CloseBuffer(0);
912                     ret = FALSE;
913                     input_file_name = NULL;
914                 }
915                 else
916                 {
917                     file_name_bufPS.CloseBuffer(length);
918                     input_file_name = file_name_buf;
919                 }
920             }
921             else
922             {
923                 ret = FALSE;
924                 input_file_name=NULL;
925             }
926         }
927     }
928     else
929     {
930         input_file_name=traced_apis_file;
931     }
932
933     if(input_file_name)
934     { 
935 #ifdef PLATFORM_UNIX
936         hFile = PAL_fopen(input_file_name, "r+");
937 #else
938         hFile = fopen(input_file_name, "r+");
939 #endif
940         if ( hFile == NULL )
941         {
942             memset(pal_function_map, 1, PAL_API_NUMBER);
943             ret = FALSE;
944         }
945         else
946         {
947             memset(pal_function_map, 0, PAL_API_NUMBER);
948
949             PAL_fseek(hFile, 0L, SEEK_SET);
950
951             /* Read a line of data from file: */
952             while ( PAL_fgets(line, PAL_PERF_MAX_INPUT, hFile) != NULL )
953             {
954                 if(strlen(line)==0)
955                     continue;
956                 ptr = strchr( line, '#');
957                 if( ptr )
958                     continue;
959                 sscanf_s(line, "%s %u", function_name,&index);
960
961                 if( index >= PAL_API_NUMBER)
962                 {
963                         // some code here to deal with incorrect index.
964                         // use function name to cover it.
965                 }
966                 else if(pal_function_map[index]==1)
967                 {
968                     // some code here to deal with conflict index.
969                     // use function name to cover it.
970                 }
971                 else
972                 {
973                     pal_function_map[index]=1;
974                 }
975
976             }
977
978 #ifdef PLATFORM_UNIX       
979             PAL_fclose(hFile);
980 #else
981             fclose(hFile);
982 #endif
983             ret = TRUE;
984         }
985     }
986     else
987     {
988         memset(pal_function_map, 1, PAL_API_NUMBER);
989         ret = FALSE;
990     }
991
992     if( enabledapis_path == NULL)
993     {
994         if(perf_default_path==NULL)
995         {
996             input_file_name = NULL;
997         }
998         else
999         {
1000             if( PERFIsValidFile(perf_default_path,perf_enabled_filename))
1001             {
1002                 if ((strcpy_s(file_name_buf, sizeof(file_name_buf), perf_default_path) != SAFECRT_SUCCESS) ||
1003                     (strcat_s(file_name_buf, sizeof(file_name_buf), PATH_SEPARATOR) != SAFECRT_SUCCESS) ||
1004                     (strcat_s(file_name_buf, sizeof(file_name_buf), perf_enabled_filename) != SAFECRT_SUCCESS))
1005                 {
1006                     ret = FALSE;
1007                     input_file_name = NULL;
1008                 }
1009                 else
1010                 {
1011                     input_file_name = file_name_buf;
1012                 }
1013             }
1014             else
1015             {
1016                input_file_name=NULL;
1017             }
1018         }
1019     }
1020     else
1021     {
1022         input_file_name=enabledapis_path;
1023     }
1024
1025     if(input_file_name == NULL)
1026     {
1027         return ret; 
1028     }
1029
1030 #ifdef PLATFORM_UNIX
1031     hFile = PAL_fopen(input_file_name, "r+");
1032 #else
1033     hFile = fopen(input_file_name, "r+");
1034 #endif
1035
1036     if ( hFile != NULL )
1037     {
1038         PAL_fseek(hFile, 0L, SEEK_SET);
1039
1040         /* Read a line of data from file: */
1041         while (PAL_fgets(line, PAL_PERF_MAX_INPUT, hFile) != NULL)
1042         {
1043             if(strlen(line)==0)
1044                 continue;
1045             ptr = strchr( line, '#');
1046             if( ptr )
1047                 continue;
1048             sscanf_s(line, "%s %u", function_name,&index);
1049
1050             if( index >= PAL_API_NUMBER)
1051             {
1052                 // some code here to deal with incorrect index.
1053                 // use function name to cover it.
1054                 continue; 
1055             }
1056
1057             if (strcpy_s(API_list[index], sizeof(API_list[index]), function_name) != SAFECRT_SUCCESS)
1058             {
1059                 ret = FALSE;
1060                 break;
1061             }
1062         }
1063
1064 #ifdef PLATFORM_UNIX       
1065         PAL_fclose(hFile);
1066 #else
1067         fclose(hFile);
1068 #endif
1069     }
1070
1071     return ret;
1072
1073 }
1074
1075
1076 static
1077 BOOL
1078 PERFFlushLog(pal_perf_thread_info * local_info, BOOL output_header)
1079 {
1080     BOOL ret = FALSE;
1081     PathCharString fileName;
1082     int nWrittenBytes = 0;
1083     PERF_FILE * hFile;
1084
1085     if (summary_only)
1086         return TRUE;
1087
1088     PERFLogFileName(fileName, profile_time_log_name, "_perf_time.log");
1089
1090     hFile = PERF_FILEFN(fopen)(fileName, "a+");
1091
1092     if(hFile)
1093     {   
1094         if (output_header)
1095         {
1096             PERFPrintProgramHeaderInfo(hFile, FALSE);
1097         }
1098         if (local_info->buf_offset > 0)
1099         {
1100             nWrittenBytes = PERF_FILEFN(fwrite)(local_info->pal_write_buf, local_info->buf_offset, 1, hFile);           
1101             if (nWrittenBytes < 1)
1102             {
1103                 ERROR("fwrite() failed with errno == %d\n", errno);
1104                 return ret;
1105             }
1106             local_info->buf_offset = 0;
1107         }
1108         PERF_FILEFN(fclose)(hFile);
1109         ret = TRUE;
1110     }
1111     
1112     return ret;
1113 }
1114
1115 void
1116 PERFLogFunctionEntry(unsigned int pal_api_id, ULONGLONG *pal_perf_start_tick )
1117 {
1118     pal_perf_thread_info * local_info=NULL;
1119     pal_perf_api_info * table;
1120     char * write_buf;
1121     __int32  buf_off;
1122     short bufused = 0;
1123
1124
1125 #ifndef PLATFORM_UNIX
1126     DWORD tv;
1127     DWORD last_error;
1128     last_error = GetLastError();
1129 #else
1130     struct timeval tv;
1131 #endif
1132
1133
1134     if(!pal_perf_enabled || pal_function_map==NULL || !pal_profile_on )  // haven't initialize, just quit.
1135         return;
1136  
1137     if( pal_function_map[pal_api_id] )
1138     {
1139         local_info= (pal_perf_thread_info * )pthread_getspecific(PERF_tlsTableKey);
1140   
1141         if (local_info==NULL  )
1142         {
1143             return;
1144         }
1145         if ( !local_info->profile_enabled ) /*  prevent recursion. */
1146         {
1147             return;
1148         }
1149         // turn on this flag before call any other functions
1150         local_info->profile_enabled = FALSE; 
1151         table = local_info->api_table;
1152         table[pal_api_id].entries++;
1153
1154         if(!summary_only)
1155         {            
1156             write_buf = (local_info->pal_write_buf);
1157             if(local_info->buf_offset >= PAL_PERF_BUFFER_FULL)
1158             {
1159                 PERFFlushLog(local_info, FALSE);
1160             }
1161
1162 #ifndef PLATFORM_UNIX
1163             tv = GetTickCount();
1164 #else
1165             gettimeofday(&tv, NULL);
1166 #endif
1167
1168             buf_off = local_info->buf_offset;
1169
1170 #ifndef PLATFORM_UNIX
1171             bufused = snprintf(&write_buf[buf_off], PAL_PERF_MAX_LOGLINE, "----> %d %lu entry.\n", pal_api_id, tv );
1172 #else
1173             bufused = snprintf(&write_buf[buf_off], PAL_PERF_MAX_LOGLINE, "----> %d %lu %06u entry.\n", pal_api_id, tv.tv_sec,  tv.tv_usec );
1174 #endif
1175             local_info->buf_offset += bufused;
1176         }
1177         if(nested_tracing)
1178             local_info->profile_enabled = TRUE; 
1179         *pal_perf_start_tick = PERFGetTicks();
1180     }
1181 #ifndef PLATFORM_UNIX
1182     SetLastError( last_error );
1183 #endif
1184     return;
1185 }
1186
1187 static
1188 void
1189 PERFUpdateApiInfo(pal_perf_api_info *api, ULONGLONG duration)
1190 {
1191     DWORD iBucket;
1192
1193     api->counter++;
1194     if (api->min_duration > duration)
1195         api->min_duration = duration;
1196     if (api->max_duration < duration)
1197         api->max_duration = duration;
1198     api->sum_duration += duration;
1199     api->sum_of_square_duration += (double) duration * (double)duration;
1200
1201     if (pal_perf_histogram_size > 0)
1202     {
1203         iBucket = (DWORD)(duration / pal_perf_histogram_step);
1204         if (iBucket >= pal_perf_histogram_size)
1205         {
1206             iBucket = pal_perf_histogram_size - 1;
1207         }
1208         api->histograms[iBucket]++;
1209     }
1210     
1211 }
1212
1213 void 
1214 PERFLogFunctionExit(unsigned int pal_api_id, ULONGLONG *pal_perf_start_tick )
1215 {
1216
1217     pal_perf_thread_info * local_info;
1218     char * buf;
1219     short bufused = 0;
1220     DWORD  off;
1221     ULONGLONG duration = 0;
1222 #ifndef PLATFORM_UNIX
1223     DWORD timev;
1224     DWORD last_error;
1225     last_error = GetLastError();
1226 #else
1227     struct timeval timev;
1228
1229 #endif
1230
1231     if(!pal_perf_enabled || (pal_function_map == NULL) || !pal_profile_on ) // haven't initiallize yet, just quit.
1232         return;
1233
1234     if (*pal_perf_start_tick != 0)
1235     {
1236         duration = PERFGetTicks() - *pal_perf_start_tick;
1237     } 
1238     else
1239     {
1240         return; // pal_perf_start_tick == 0 indicates that we exited PERFLogFunctionEntry before getting the ticks.
1241     }
1242
1243     if( pal_function_map[pal_api_id] )
1244     {
1245         local_info = (pal_perf_thread_info*)pthread_getspecific(PERF_tlsTableKey);
1246
1247         if (NULL == local_info ){
1248             return;
1249         }
1250         PERFUpdateApiInfo(&local_info->api_table[pal_api_id], duration);
1251         *pal_perf_start_tick = 0;
1252            
1253         if(summary_only)
1254         {
1255             local_info->profile_enabled = TRUE;
1256 #ifndef PLATFORM_UNIX
1257             SetLastError( last_error );
1258 #endif
1259             return;
1260         }
1261
1262 #ifndef PLATFORM_UNIX
1263         timev = GetTickCount();
1264 #else
1265         gettimeofday(&timev, NULL);
1266 #endif
1267
1268         buf = local_info->pal_write_buf;
1269         if(local_info->buf_offset >= PAL_PERF_BUFFER_FULL)
1270         {
1271             PERFFlushLog(local_info, FALSE);
1272         }
1273         off = local_info->buf_offset;
1274
1275 #ifndef PLATFORM_UNIX
1276         bufused = snprintf(&buf[off], PAL_PERF_MAX_LOGLINE, "<---- %d %lu exit. \n", pal_api_id, timev);
1277 #else
1278         bufused = snprintf(&buf[off], PAL_PERF_MAX_LOGLINE, "<---- %d %lu %06u exit. \n", pal_api_id, timev.tv_sec,  timev.tv_usec );
1279 #endif
1280         local_info->buf_offset += bufused;
1281         local_info->profile_enabled = TRUE;  
1282     }
1283 #ifndef PLATFORM_UNIX
1284     SetLastError( last_error );
1285 #endif
1286     return;
1287 }
1288
1289 void
1290 PERFNoLatencyProfileEntry(unsigned int pal_api_id )
1291 {
1292     pal_perf_thread_info * local_info=NULL;
1293     pal_perf_api_info * table;
1294 #ifndef PLATFORM_UNIX
1295     DWORD last_error;
1296     last_error = GetLastError();
1297 #endif
1298
1299     if(!pal_perf_enabled || pal_function_map==NULL || !pal_profile_on )  // haven't initialize, just quit.
1300         return;
1301     if( pal_function_map[pal_api_id] )
1302     {
1303          local_info= (pal_perf_thread_info * )pthread_getspecific(PERF_tlsTableKey);
1304          if (local_info==NULL  )
1305          {
1306 #ifndef PLATFORM_UNIX
1307             SetLastError( last_error );
1308 #endif
1309             return;
1310          }
1311          else{
1312             table = local_info->api_table;
1313             table[pal_api_id].entries++;
1314         }
1315    }
1316 #ifndef PLATFORM_UNIX
1317     SetLastError( last_error );
1318 #endif
1319    return;
1320 }
1321
1322
1323 void
1324 PERFEnableThreadProfile(BOOL isInternal)
1325 {
1326     pal_perf_thread_info * local_info;
1327 #ifndef PLATFORM_UNIX
1328     DWORD last_error;
1329     last_error = GetLastError();
1330 #endif
1331     if (!pal_perf_enabled)
1332         return;
1333     if (NULL != (local_info = (pal_perf_thread_info*)pthread_getspecific(PERF_tlsTableKey)))
1334     {
1335          if (!isInternal || nested_tracing) {
1336             local_info->profile_enabled = TRUE;
1337             local_info->start_ticks = PERFGetTicks();
1338          }
1339     }
1340 #ifndef PLATFORM_UNIX
1341     SetLastError( last_error );
1342 #endif
1343 }
1344
1345
1346 void
1347 PERFDisableThreadProfile(BOOL isInternal)
1348 {
1349     pal_perf_thread_info * local_info;
1350 #ifndef PLATFORM_UNIX
1351     DWORD last_error;
1352     last_error = GetLastError();
1353 #endif
1354     if (!pal_perf_enabled)
1355         return;
1356     if (NULL != (local_info = (pal_perf_thread_info*)pthread_getspecific(PERF_tlsTableKey)))
1357     {
1358          if (!isInternal || nested_tracing) {
1359             local_info->profile_enabled = FALSE;
1360             local_info->total_duration = PERFGetTicks() - local_info->start_ticks;
1361          }
1362     }
1363 #ifndef PLATFORM_UNIX
1364     SetLastError( last_error );
1365 #endif
1366 }
1367
1368
1369 void
1370 PERFEnableProcessProfile(  )
1371 {
1372     if (!pal_perf_enabled || wait_for_startup)
1373         return;
1374     pal_profile_on = TRUE;
1375     PERFCalibrate("Overhead when profiling is disabled temporarily for a thread");
1376     // record the cpu clock ticks at the beginning of the profiling.
1377     program_info.start_ticks = PERFGetTicks();
1378 }
1379
1380
1381 void
1382 PERFDisableProcessProfile( )
1383 {
1384     if (!pal_perf_enabled)
1385         return;
1386     pal_profile_on = FALSE;
1387     // compute the total program duration in cpu clock ticks.
1388     if (program_info.start_ticks != 0)
1389     {
1390         program_info.elapsed_time += (PERFGetTicks() - program_info.start_ticks);
1391         program_info.start_ticks = 0;
1392     }
1393 }
1394
1395 BOOL
1396 PERFIsProcessProfileEnabled(  )
1397 {
1398     return pal_profile_on;
1399 }
1400
1401 static
1402 char *
1403 PERFIsValidPath( const char * path )
1404 {
1405 #ifndef PLATFORM_UNIX
1406     DWORD result;
1407 #else
1408     DIR * dir;
1409 #endif
1410
1411     if(( path==NULL) || (strlen(path)==0))
1412        return NULL; 
1413
1414 #ifndef PLATFORM_UNIX
1415     result = GetFileAttributesA( path );
1416     if ((result != INVALID_FILE_ATTRIBUTES) && (result & FILE_ATTRIBUTE_DIRECTORY))
1417     {
1418         return ((char *) path );
1419     }
1420 #else
1421     dir = opendir(path);
1422     if( dir!=NULL)
1423     {
1424         closedir(dir);
1425         return ((char *)path);
1426     }
1427 #endif
1428     return NULL;
1429 }
1430
1431 static
1432 char * 
1433 PERFIsValidFile( const char * path, const char * file)
1434 {
1435     FILE * hFile;
1436     char * temp;
1437     PathCharString tempPS;
1438
1439     if(file==NULL || strlen(file)==0) 
1440         return NULL;
1441
1442         if ( strcmp(path, "") )
1443     {
1444         int length = strlen(path) + strlen(PATH_SEPARATOR) + strlen(file);
1445         temp = tempPS.OpenStringBuffer(length);   
1446         if ((strcpy_s(temp, sizeof(temp), path) != SAFECRT_SUCCESS) ||
1447             (strcat_s(temp, sizeof(temp), PATH_SEPARATOR) != SAFECRT_SUCCESS) ||
1448             (strcat_s(temp, sizeof(temp), file) != SAFECRT_SUCCESS))
1449         {
1450             tempPS.CloseBuffer(0);
1451             return NULL;
1452         }
1453
1454         tempPS.CloseBuffer(length);
1455         hFile = fopen(temp, "r");
1456     }
1457     else
1458         {
1459         hFile = fopen(file, "r");
1460         }
1461
1462     if(hFile)
1463     {
1464             fclose(hFile);
1465         return ((char *) file);
1466     }
1467         else
1468                 return NULL;
1469
1470 }
1471
1472 PALIMPORT
1473 VOID
1474 PALAPI
1475 PAL_EnableProcessProfile(VOID)
1476 {
1477     wait_for_startup = FALSE;
1478     pal_profile_on = TRUE;
1479     PERFEnableProcessProfile();
1480 }
1481
1482 PALIMPORT
1483 VOID
1484 PALAPI
1485 PAL_DisableProcessProfile(VOID)
1486 {
1487     pal_profile_on = FALSE;
1488     PERFDisableProcessProfile();
1489 }
1490
1491 PALIMPORT
1492 BOOL
1493 PALAPI
1494 PAL_IsProcessProfileEnabled(VOID)
1495 {
1496     return PERFIsProcessProfileEnabled();
1497 }
1498
1499 PALIMPORT
1500 INT64
1501 PALAPI
1502 PAL_GetCpuTickCount(VOID)
1503 {
1504     return PERFGetTicks();
1505 }
1506
1507 #ifndef PLATFORM_UNIX
1508 #undef snprintf 
1509 #undef MiscGetenv
1510 #undef pthread_key_t
1511 #undef pthread_getspecific
1512 #endif /* ifndef PLATFORM_UNIX definitions */
1513
1514 #endif /* PAL_PERF */
1515
1516
1517
1518