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