1/*===-- CommonProfiling.c - Profiling support library support -------------===*\ 2|* 3|* The LLVM Compiler Infrastructure 4|* 5|* This file is distributed under the University of Illinois Open Source 6|* License. See LICENSE.TXT for details. 7|* 8|*===----------------------------------------------------------------------===*| 9|* 10|* This file implements functions used by the various different types of 11|* profiling implementations. 12|* 13\*===----------------------------------------------------------------------===*/ 14 15#include "Profiling.h" 16#include <assert.h> 17#include <sys/types.h> 18#include <sys/stat.h> 19#include <fcntl.h> 20#include <stdio.h> 21#include <string.h> 22#if !defined(_MSC_VER) && !defined(__MINGW32__) 23#include <unistd.h> 24#else 25#include <io.h> 26#endif 27#include <stdlib.h> 28 29static char *SavedArgs = 0; 30static unsigned SavedArgsLength = 0; 31 32static const char *OutputFilename = "llvmprof.out"; 33 34/* save_arguments - Save argc and argv as passed into the program for the file 35 * we output. 36 */ 37int save_arguments(int argc, const char **argv) { 38 unsigned Length, i; 39 if (SavedArgs || !argv) return argc; /* This can be called multiple times */ 40 41 /* Check to see if there are any arguments passed into the program for the 42 * profiler. If there are, strip them off and remember their settings. 43 */ 44 while (argc > 1 && !strncmp(argv[1], "-llvmprof-", 10)) { 45 /* Ok, we have an llvmprof argument. Remove it from the arg list and decide 46 * what to do with it. 47 */ 48 const char *Arg = argv[1]; 49 memmove((char**)&argv[1], &argv[2], (argc-1)*sizeof(char*)); 50 --argc; 51 52 if (!strcmp(Arg, "-llvmprof-output")) { 53 if (argc == 1) 54 puts("-llvmprof-output requires a filename argument!"); 55 else { 56 OutputFilename = strdup(argv[1]); 57 memmove((char**)&argv[1], &argv[2], (argc-1)*sizeof(char*)); 58 --argc; 59 } 60 } else { 61 printf("Unknown option to the profiler runtime: '%s' - ignored.\n", Arg); 62 } 63 } 64 65 for (Length = 0, i = 0; i != (unsigned)argc; ++i) 66 Length += strlen(argv[i])+1; 67 68 /* Defensively check for a zero length, even though this is unlikely 69 * to happen in practice. This avoids calling malloc() below with a 70 * size of 0. 71 */ 72 if (Length == 0) { 73 SavedArgs = 0; 74 SavedArgsLength = 0; 75 return argc; 76 } 77 78 SavedArgs = (char*)malloc(Length); 79 for (Length = 0, i = 0; i != (unsigned)argc; ++i) { 80 unsigned Len = strlen(argv[i]); 81 memcpy(SavedArgs+Length, argv[i], Len); 82 Length += Len; 83 SavedArgs[Length++] = ' '; 84 } 85 86 SavedArgsLength = Length; 87 88 return argc; 89} 90 91 92/* 93 * Retrieves the file descriptor for the profile file. 94 */ 95int getOutFile() { 96 static int OutFile = -1; 97 98 /* If this is the first time this function is called, open the output file 99 * for appending, creating it if it does not already exist. 100 */ 101 if (OutFile == -1) { 102 OutFile = open(OutputFilename, O_CREAT | O_WRONLY, 0666); 103 lseek(OutFile, 0, SEEK_END); /* O_APPEND prevents seeking */ 104 if (OutFile == -1) { 105 fprintf(stderr, "LLVM profiling runtime: while opening '%s': ", 106 OutputFilename); 107 perror(""); 108 return(OutFile); 109 } 110 111 /* Output the command line arguments to the file. */ 112 { 113 int PTy = ArgumentInfo; 114 int Zeros = 0; 115 if (write(OutFile, &PTy, sizeof(int)) < 0 || 116 write(OutFile, &SavedArgsLength, sizeof(unsigned)) < 0 || 117 write(OutFile, SavedArgs, SavedArgsLength) < 0 ) { 118 fprintf(stderr,"error: unable to write to output file."); 119 exit(0); 120 } 121 /* Pad out to a multiple of four bytes */ 122 if (SavedArgsLength & 3) { 123 if (write(OutFile, &Zeros, 4-(SavedArgsLength&3)) < 0) { 124 fprintf(stderr,"error: unable to write to output file."); 125 exit(0); 126 } 127 } 128 } 129 } 130 return(OutFile); 131} 132 133/* write_profiling_data - Write a raw block of profiling counters out to the 134 * llvmprof.out file. Note that we allow programs to be instrumented with 135 * multiple different kinds of instrumentation. For this reason, this function 136 * may be called more than once. 137 */ 138void write_profiling_data(enum ProfilingType PT, unsigned *Start, 139 unsigned NumElements) { 140 int PTy; 141 int outFile = getOutFile(); 142 143 /* Write out this record! */ 144 PTy = PT; 145 if( write(outFile, &PTy, sizeof(int)) < 0 || 146 write(outFile, &NumElements, sizeof(unsigned)) < 0 || 147 write(outFile, Start, NumElements*sizeof(unsigned)) < 0 ) { 148 fprintf(stderr,"error: unable to write to output file."); 149 exit(0); 150 } 151} 152