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