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