1 /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\ 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 #include "InstrProfiling.h" 11 #include "InstrProfilingInternal.h" 12 #include "InstrProfilingUtil.h" 13 #include <errno.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #ifdef _MSC_VER 18 /* For _alloca. */ 19 #include <malloc.h> 20 #endif 21 #if defined(_WIN32) 22 #include "WindowsMMap.h" 23 /* For _chsize_s */ 24 #include <io.h> 25 #else 26 #include <sys/file.h> 27 #include <sys/mman.h> 28 #include <unistd.h> 29 #if defined(__linux__) 30 #include <sys/types.h> 31 #endif 32 #endif 33 34 /* From where is profile name specified. 35 * The order the enumerators define their 36 * precedence. Re-order them may lead to 37 * runtime behavior change. */ 38 typedef enum ProfileNameSpecifier { 39 PNS_unknown = 0, 40 PNS_default, 41 PNS_command_line, 42 PNS_environment, 43 PNS_runtime_api 44 } ProfileNameSpecifier; 45 46 static const char *getPNSStr(ProfileNameSpecifier PNS) { 47 switch (PNS) { 48 case PNS_default: 49 return "default setting"; 50 case PNS_command_line: 51 return "command line"; 52 case PNS_environment: 53 return "environment variable"; 54 case PNS_runtime_api: 55 return "runtime API"; 56 default: 57 return "Unknown"; 58 } 59 } 60 61 #define MAX_PID_SIZE 16 62 /* Data structure holding the result of parsed filename pattern. */ 63 typedef struct lprofFilename { 64 /* File name string possibly with %p or %h specifiers. */ 65 const char *FilenamePat; 66 char PidChars[MAX_PID_SIZE]; 67 char Hostname[COMPILER_RT_MAX_HOSTLEN]; 68 unsigned NumPids; 69 unsigned NumHosts; 70 /* When in-process merging is enabled, this parameter specifies 71 * the total number of profile data files shared by all the processes 72 * spawned from the same binary. By default the value is 1. If merging 73 * is not enabled, its value should be 0. This parameter is specified 74 * by the %[0-9]m specifier. For instance %2m enables merging using 75 * 2 profile data files. %1m is equivalent to %m. Also %m specifier 76 * can only appear once at the end of the name pattern. */ 77 unsigned MergePoolSize; 78 ProfileNameSpecifier PNS; 79 } lprofFilename; 80 81 lprofFilename lprofCurFilename = {0, {0}, {0}, 0, 0, 0, PNS_unknown}; 82 83 int getpid(void); 84 static int getCurFilenameLength(); 85 static const char *getCurFilename(char *FilenameBuf); 86 static unsigned doMerging() { return lprofCurFilename.MergePoolSize; } 87 88 /* Return 1 if there is an error, otherwise return 0. */ 89 static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, 90 void **WriterCtx) { 91 uint32_t I; 92 FILE *File = (FILE *)*WriterCtx; 93 for (I = 0; I < NumIOVecs; I++) { 94 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != 95 IOVecs[I].NumElm) 96 return 1; 97 } 98 return 0; 99 } 100 101 COMPILER_RT_VISIBILITY ProfBufferIO * 102 lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { 103 FreeHook = &free; 104 DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1); 105 VPBufferSize = BufferSz; 106 return lprofCreateBufferIO(fileWriter, File); 107 } 108 109 static void setupIOBuffer() { 110 const char *BufferSzStr = 0; 111 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); 112 if (BufferSzStr && BufferSzStr[0]) { 113 VPBufferSize = atoi(BufferSzStr); 114 DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1); 115 } 116 } 117 118 /* Read profile data in \c ProfileFile and merge with in-memory 119 profile counters. Returns -1 if there is fatal error, otheriwse 120 0 is returned. 121 */ 122 static int doProfileMerging(FILE *ProfileFile) { 123 uint64_t ProfileFileSize; 124 char *ProfileBuffer; 125 126 if (fseek(ProfileFile, 0L, SEEK_END) == -1) { 127 PROF_ERR("Unable to merge profile data, unable to get size: %s\n", 128 strerror(errno)); 129 return -1; 130 } 131 ProfileFileSize = ftell(ProfileFile); 132 133 /* Restore file offset. */ 134 if (fseek(ProfileFile, 0L, SEEK_SET) == -1) { 135 PROF_ERR("Unable to merge profile data, unable to rewind: %s\n", 136 strerror(errno)); 137 return -1; 138 } 139 140 /* Nothing to merge. */ 141 if (ProfileFileSize < sizeof(__llvm_profile_header)) { 142 if (ProfileFileSize) 143 PROF_WARN("Unable to merge profile data: %s\n", 144 "source profile file is too small."); 145 return 0; 146 } 147 148 ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE, 149 fileno(ProfileFile), 0); 150 if (ProfileBuffer == MAP_FAILED) { 151 PROF_ERR("Unable to merge profile data, mmap failed: %s\n", 152 strerror(errno)); 153 return -1; 154 } 155 156 if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) { 157 (void)munmap(ProfileBuffer, ProfileFileSize); 158 PROF_WARN("Unable to merge profile data: %s\n", 159 "source profile file is not compatible."); 160 return 0; 161 } 162 163 /* Now start merging */ 164 __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); 165 (void)munmap(ProfileBuffer, ProfileFileSize); 166 167 return 0; 168 } 169 170 /* Open the profile data for merging. It opens the file in r+b mode with 171 * file locking. If the file has content which is compatible with the 172 * current process, it also reads in the profile data in the file and merge 173 * it with in-memory counters. After the profile data is merged in memory, 174 * the original profile data is truncated and gets ready for the profile 175 * dumper. With profile merging enabled, each executable as well as any of 176 * its instrumented shared libraries dump profile data into their own data file. 177 */ 178 static FILE *openFileForMerging(const char *ProfileFileName) { 179 FILE *ProfileFile; 180 int rc; 181 182 ProfileFile = lprofOpenFileEx(ProfileFileName); 183 if (!ProfileFile) 184 return NULL; 185 186 rc = doProfileMerging(ProfileFile); 187 if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) || 188 fseek(ProfileFile, 0L, SEEK_SET) == -1) { 189 PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, 190 strerror(errno)); 191 fclose(ProfileFile); 192 return NULL; 193 } 194 fseek(ProfileFile, 0L, SEEK_SET); 195 return ProfileFile; 196 } 197 198 /* Write profile data to file \c OutputName. */ 199 static int writeFile(const char *OutputName) { 200 int RetVal; 201 FILE *OutputFile; 202 203 if (!doMerging()) 204 OutputFile = fopen(OutputName, "ab"); 205 else 206 OutputFile = openFileForMerging(OutputName); 207 208 if (!OutputFile) 209 return -1; 210 211 FreeHook = &free; 212 setupIOBuffer(); 213 RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader()); 214 215 fclose(OutputFile); 216 return RetVal; 217 } 218 219 static void truncateCurrentFile(void) { 220 const char *Filename; 221 char *FilenameBuf; 222 FILE *File; 223 int Length; 224 225 Length = getCurFilenameLength(); 226 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 227 Filename = getCurFilename(FilenameBuf); 228 if (!Filename) 229 return; 230 231 /* Create the directory holding the file, if needed. */ 232 if (strchr(Filename, '/') || strchr(Filename, '\\')) { 233 char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); 234 strncpy(Copy, Filename, Length + 1); 235 __llvm_profile_recursive_mkdir(Copy); 236 } 237 238 /* Truncate the file. Later we'll reopen and append. */ 239 File = fopen(Filename, "w"); 240 if (!File) 241 return; 242 fclose(File); 243 } 244 245 static const char *DefaultProfileName = "default.profraw"; 246 static void resetFilenameToDefault(void) { 247 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 248 lprofCurFilename.FilenamePat = DefaultProfileName; 249 lprofCurFilename.PNS = PNS_default; 250 } 251 252 static int containsMergeSpecifier(const char *FilenamePat, int I) { 253 return (FilenamePat[I] == 'm' || 254 (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' && 255 /* If FilenamePat[I] is not '\0', the next byte is guaranteed 256 * to be in-bound as the string is null terminated. */ 257 FilenamePat[I + 1] == 'm')); 258 } 259 260 /* Parses the pattern string \p FilenamePat and stores the result to 261 * lprofcurFilename structure. */ 262 static int parseFilenamePattern(const char *FilenamePat) { 263 int NumPids = 0, NumHosts = 0, I; 264 char *PidChars = &lprofCurFilename.PidChars[0]; 265 char *Hostname = &lprofCurFilename.Hostname[0]; 266 int MergingEnabled = 0; 267 268 lprofCurFilename.FilenamePat = FilenamePat; 269 /* Check the filename for "%p", which indicates a pid-substitution. */ 270 for (I = 0; FilenamePat[I]; ++I) 271 if (FilenamePat[I] == '%') { 272 if (FilenamePat[++I] == 'p') { 273 if (!NumPids++) { 274 if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) { 275 PROF_WARN( 276 "Unable to parse filename pattern %s. Using the default name.", 277 FilenamePat); 278 return -1; 279 } 280 } 281 } else if (FilenamePat[I] == 'h') { 282 if (!NumHosts++) 283 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { 284 PROF_WARN( 285 "Unable to parse filename pattern %s. Using the default name.", 286 FilenamePat); 287 return -1; 288 } 289 } else if (containsMergeSpecifier(FilenamePat, I)) { 290 if (MergingEnabled) { 291 PROF_WARN("%%m specifier can only be specified once in %s.\n", 292 FilenamePat); 293 return -1; 294 } 295 MergingEnabled = 1; 296 if (FilenamePat[I] == 'm') 297 lprofCurFilename.MergePoolSize = 1; 298 else { 299 lprofCurFilename.MergePoolSize = FilenamePat[I] - '0'; 300 I++; /* advance to 'm' */ 301 } 302 } 303 } 304 305 lprofCurFilename.NumPids = NumPids; 306 lprofCurFilename.NumHosts = NumHosts; 307 return 0; 308 } 309 310 static void parseAndSetFilename(const char *FilenamePat, 311 ProfileNameSpecifier PNS) { 312 313 const char *OldFilenamePat = lprofCurFilename.FilenamePat; 314 ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; 315 316 if (PNS < OldPNS) 317 return; 318 319 if (!FilenamePat) 320 FilenamePat = DefaultProfileName; 321 322 /* When -fprofile-instr-generate=<path> is specified on the 323 * command line, each module will be instrumented with runtime 324 * init call to __llvm_profile_init function which calls 325 * __llvm_profile_override_default_filename. In most of the cases, 326 * the path will be identical, so bypass the parsing completely. 327 */ 328 if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { 329 lprofCurFilename.PNS = PNS; 330 return; 331 } 332 333 /* When PNS >= OldPNS, the last one wins. */ 334 if (!FilenamePat || parseFilenamePattern(FilenamePat)) 335 resetFilenameToDefault(); 336 lprofCurFilename.PNS = PNS; 337 338 if (!OldFilenamePat) { 339 PROF_NOTE("Set profile file path to \"%s\" via %s.\n", 340 lprofCurFilename.FilenamePat, getPNSStr(PNS)); 341 } else { 342 PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", 343 OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, 344 getPNSStr(PNS)); 345 } 346 347 if (!lprofCurFilename.MergePoolSize) 348 truncateCurrentFile(); 349 } 350 351 /* Return buffer length that is required to store the current profile 352 * filename with PID and hostname substitutions. */ 353 /* The length to hold uint64_t followed by 2 digit pool id including '_' */ 354 #define SIGLEN 24 355 static int getCurFilenameLength() { 356 int Len; 357 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 358 return 0; 359 360 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 361 lprofCurFilename.MergePoolSize)) 362 return strlen(lprofCurFilename.FilenamePat); 363 364 Len = strlen(lprofCurFilename.FilenamePat) + 365 lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + 366 lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2); 367 if (lprofCurFilename.MergePoolSize) 368 Len += SIGLEN; 369 return Len; 370 } 371 372 /* Return the pointer to the current profile file name (after substituting 373 * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer 374 * to store the resulting filename. If no substitution is needed, the 375 * current filename pattern string is directly returned. */ 376 static const char *getCurFilename(char *FilenameBuf) { 377 int I, J, PidLength, HostNameLength; 378 const char *FilenamePat = lprofCurFilename.FilenamePat; 379 380 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 381 return 0; 382 383 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 384 lprofCurFilename.MergePoolSize)) 385 return lprofCurFilename.FilenamePat; 386 387 PidLength = strlen(lprofCurFilename.PidChars); 388 HostNameLength = strlen(lprofCurFilename.Hostname); 389 /* Construct the new filename. */ 390 for (I = 0, J = 0; FilenamePat[I]; ++I) 391 if (FilenamePat[I] == '%') { 392 if (FilenamePat[++I] == 'p') { 393 memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); 394 J += PidLength; 395 } else if (FilenamePat[I] == 'h') { 396 memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); 397 J += HostNameLength; 398 } else if (containsMergeSpecifier(FilenamePat, I)) { 399 char LoadModuleSignature[SIGLEN]; 400 int S; 401 int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize; 402 S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d", 403 lprofGetLoadModuleSignature(), ProfilePoolId); 404 if (S == -1 || S > SIGLEN) 405 S = SIGLEN; 406 memcpy(FilenameBuf + J, LoadModuleSignature, S); 407 J += S; 408 if (FilenamePat[I] != 'm') 409 I++; 410 } 411 /* Drop any unknown substitutions. */ 412 } else 413 FilenameBuf[J++] = FilenamePat[I]; 414 FilenameBuf[J] = 0; 415 416 return FilenameBuf; 417 } 418 419 /* Returns the pointer to the environment variable 420 * string. Returns null if the env var is not set. */ 421 static const char *getFilenamePatFromEnv(void) { 422 const char *Filename = getenv("LLVM_PROFILE_FILE"); 423 if (!Filename || !Filename[0]) 424 return 0; 425 return Filename; 426 } 427 428 /* This method is invoked by the runtime initialization hook 429 * InstrProfilingRuntime.o if it is linked in. Both user specified 430 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE 431 * environment variable can override this default value. */ 432 COMPILER_RT_VISIBILITY 433 void __llvm_profile_initialize_file(void) { 434 const char *FilenamePat; 435 436 FilenamePat = getFilenamePatFromEnv(); 437 parseAndSetFilename(FilenamePat, FilenamePat ? PNS_environment : PNS_default); 438 } 439 440 /* This API is directly called by the user application code. It has the 441 * highest precedence compared with LLVM_PROFILE_FILE environment variable 442 * and command line option -fprofile-instr-generate=<profile_name>. 443 */ 444 COMPILER_RT_VISIBILITY 445 void __llvm_profile_set_filename(const char *FilenamePat) { 446 parseAndSetFilename(FilenamePat, PNS_runtime_api); 447 } 448 449 /* 450 * This API is invoked by the global initializers emitted by Clang/LLVM when 451 * -fprofile-instr-generate=<..> is specified (vs -fprofile-instr-generate 452 * without an argument). This option has lower precedence than the 453 * LLVM_PROFILE_FILE environment variable. 454 */ 455 COMPILER_RT_VISIBILITY 456 void __llvm_profile_override_default_filename(const char *FilenamePat) { 457 parseAndSetFilename(FilenamePat, PNS_command_line); 458 } 459 460 /* The public API for writing profile data into the file with name 461 * set by previous calls to __llvm_profile_set_filename or 462 * __llvm_profile_override_default_filename or 463 * __llvm_profile_initialize_file. */ 464 COMPILER_RT_VISIBILITY 465 int __llvm_profile_write_file(void) { 466 int rc, Length; 467 const char *Filename; 468 char *FilenameBuf; 469 470 Length = getCurFilenameLength(); 471 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 472 Filename = getCurFilename(FilenameBuf); 473 474 /* Check the filename. */ 475 if (!Filename) { 476 PROF_ERR("Failed to write file : %s\n", "Filename not set"); 477 return -1; 478 } 479 480 /* Check if there is llvm/runtime version mismatch. */ 481 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 482 PROF_ERR("Runtime and instrumentation version mismatch : " 483 "expected %d, but get %d\n", 484 INSTR_PROF_RAW_VERSION, 485 (int)GET_VERSION(__llvm_profile_get_version())); 486 return -1; 487 } 488 489 /* Write profile data to the file. */ 490 rc = writeFile(Filename); 491 if (rc) 492 PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 493 return rc; 494 } 495 496 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } 497 498 COMPILER_RT_VISIBILITY 499 int __llvm_profile_register_write_file_atexit(void) { 500 static int HasBeenRegistered = 0; 501 502 if (HasBeenRegistered) 503 return 0; 504 505 lprofSetupValueProfiler(); 506 507 HasBeenRegistered = 1; 508 return atexit(writeFileWithoutReturn); 509 } 510