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