forked from OSchip/llvm-project
				
			[profile] in-process mergeing support (part-2)
(Part-1 merging API is in profile runtime) This patch implements a portable file opening API with exclusive access for the process. In-process profile merge requires profile file update to be atomic/fully sychronized. llvm-svn: 271864
This commit is contained in:
		
							parent
							
								
									04a89fd826
								
							
						
					
					
						commit
						5cd1f94d4f
					
				| 
						 | 
				
			
			@ -22,6 +22,22 @@ int main() {
 | 
			
		|||
      }
 | 
			
		||||
" COMPILER_RT_TARGET_HAS_ATOMICS)
 | 
			
		||||
 | 
			
		||||
CHECK_CXX_SOURCE_COMPILES("
 | 
			
		||||
#if defined(__linux__)
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
int fd;
 | 
			
		||||
int main() {
 | 
			
		||||
 struct flock s_flock;
 | 
			
		||||
 | 
			
		||||
 s_flock.l_type = F_WRLCK;
 | 
			
		||||
 fcntl(fd, F_SETLKW, &s_flock);
 | 
			
		||||
 return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
" COMPILER_RT_TARGET_HAS_FCNTL_LCK)
 | 
			
		||||
 | 
			
		||||
add_custom_target(profile)
 | 
			
		||||
 | 
			
		||||
set(PROFILE_SOURCES
 | 
			
		||||
| 
						 | 
				
			
			@ -55,6 +71,12 @@ if(COMPILER_RT_TARGET_HAS_ATOMICS)
 | 
			
		|||
     -DCOMPILER_RT_HAS_ATOMICS=1)
 | 
			
		||||
endif() 
 | 
			
		||||
 | 
			
		||||
if(COMPILER_RT_TARGET_HAS_FCNTL_LCK)
 | 
			
		||||
 set(EXTRA_FLAGS
 | 
			
		||||
     ${EXTRA_FLAGS}
 | 
			
		||||
     -DCOMPILER_RT_HAS_FCNTL_LCK=1)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(APPLE)
 | 
			
		||||
  add_compiler_rt_runtime(clang_rt.profile
 | 
			
		||||
    STATIC
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,9 +12,15 @@
 | 
			
		|||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#include <direct.h>
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#if defined(__linux__)
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef COMPILER_RT_HAS_UNAME
 | 
			
		||||
| 
						 | 
				
			
			@ -70,4 +76,51 @@ int lprofGetHostName(char *Name, int Len) {
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
FILE *lprofOpenFileEx(const char *ProfileName) {
 | 
			
		||||
  FILE *f;
 | 
			
		||||
  int fd;
 | 
			
		||||
#ifdef COMPILER_RT_HAS_FCNTL_LCK
 | 
			
		||||
  struct flock s_flock;
 | 
			
		||||
 | 
			
		||||
  s_flock.l_whence = SEEK_SET;
 | 
			
		||||
  s_flock.l_start = 0;
 | 
			
		||||
  s_flock.l_len = 0; /* Until EOF.  */
 | 
			
		||||
  s_flock.l_pid = getpid();
 | 
			
		||||
 | 
			
		||||
  s_flock.l_type = F_WRLCK;
 | 
			
		||||
  fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
 | 
			
		||||
  if (fd < 0)
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
  while (fcntl(fd, F_SETLKW, &s_flock) && errno == EINTR)
 | 
			
		||||
    continue;
 | 
			
		||||
 | 
			
		||||
  f = fdopen(fd, "r+b");
 | 
			
		||||
#elif defined(_WIN32)
 | 
			
		||||
  HANDLE h = CreateFile(ProfileName, GENERIC_READ | GENERIC_WRITE, 0, 0,
 | 
			
		||||
                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
 | 
			
		||||
  if (h == INVALID_HANDLE_VALUE)
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
  fd = _open_osfhandle((intptr_t)h, 0);
 | 
			
		||||
  if (fd == -1) {
 | 
			
		||||
    CloseHandle(h);
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  f = _fdopen(fd, "r+b");
 | 
			
		||||
  if (f == 0) {
 | 
			
		||||
    CloseHandle(h);
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
#else
 | 
			
		||||
  /* Worst case no locking applied.  */
 | 
			
		||||
  PROF_WARN("Concurrent file access is not supported : %s\n", "lack file locking");
 | 
			
		||||
  fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
 | 
			
		||||
  if (fd < 0)
 | 
			
		||||
    return 0;
 | 
			
		||||
  f = fdopen(fd, "r+b");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  return f;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,10 +11,15 @@
 | 
			
		|||
#define PROFILE_INSTRPROFILINGUTIL_H
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
/*! \brief Create a directory tree. */
 | 
			
		||||
void __llvm_profile_recursive_mkdir(char *Pathname);
 | 
			
		||||
 | 
			
		||||
/*! Open file \c Filename for read+write with write
 | 
			
		||||
 * lock for exclusive access. The caller will block
 | 
			
		||||
 * if the lock is already held by another process. */
 | 
			
		||||
FILE *lprofOpenFileEx(const char *Filename);
 | 
			
		||||
/* PS4 doesn't have getenv. Define a shim. */
 | 
			
		||||
#if __ORBIS__
 | 
			
		||||
static inline char *getenv(const char *name) { return NULL; }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
/* This is a test case where the parent process forks 10
 | 
			
		||||
 * children which contend to write to the same file. With
 | 
			
		||||
 * file locking support, the data from each child should not
 | 
			
		||||
 * be lost.
 | 
			
		||||
 */
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/wait.h>
 | 
			
		||||
 | 
			
		||||
extern FILE *lprofOpenFileEx(const char *);
 | 
			
		||||
int main(int argc, char *argv[]) {
 | 
			
		||||
  pid_t tid;
 | 
			
		||||
  FILE *F;
 | 
			
		||||
  const char *FN;
 | 
			
		||||
  int child[10];
 | 
			
		||||
  int c;
 | 
			
		||||
  int i;
 | 
			
		||||
 | 
			
		||||
  if (argc < 2) {
 | 
			
		||||
    fprintf(stderr, "Requires one argument \n");
 | 
			
		||||
    exit(1);
 | 
			
		||||
  }
 | 
			
		||||
  FN = argv[1];
 | 
			
		||||
  truncate(FN, 0);
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < 10; i++) {
 | 
			
		||||
    c = fork();
 | 
			
		||||
    // in child: 
 | 
			
		||||
    if (c == 0) {
 | 
			
		||||
      FILE *F = lprofOpenFileEx(FN);
 | 
			
		||||
      if (!F) {
 | 
			
		||||
        fprintf(stderr, "Can not open file %s from child\n", FN);
 | 
			
		||||
        exit(1);
 | 
			
		||||
      }
 | 
			
		||||
      fseek(F, 0, SEEK_END);
 | 
			
		||||
      fprintf(F, "Dump from Child %d\n", i + 11);
 | 
			
		||||
      fclose(F);
 | 
			
		||||
      exit(0);
 | 
			
		||||
    } else {
 | 
			
		||||
      child[i] = c;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // In parent
 | 
			
		||||
  for (i = 0; i < 10; i++) {
 | 
			
		||||
    int child_status;
 | 
			
		||||
    if ((tid = waitpid(child[i], &child_status, 0) == -1))
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  F = lprofOpenFileEx(FN);
 | 
			
		||||
  if (!F) {
 | 
			
		||||
    fprintf(stderr, "Can not open file %s from parent\n", FN);
 | 
			
		||||
    exit(1);
 | 
			
		||||
  }
 | 
			
		||||
  fseek(F, 0, SEEK_END);
 | 
			
		||||
  fprintf(F, "Dump from parent %d\n", i + 11);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
RUN: mkdir -p %t.d
 | 
			
		||||
RUN: %clang_profgen -fprofile-instr-generate %S/../Inputs/instrprof-file_ex.c -o %t
 | 
			
		||||
RUN: %run %t %t.d/run.dump
 | 
			
		||||
RUN: sort %t.d/run.dump | FileCheck %s
 | 
			
		||||
 | 
			
		||||
CHECK: Dump from Child 11
 | 
			
		||||
CHECK-NEXT: Dump from Child 12
 | 
			
		||||
CHECK-NEXT: Dump from Child 13
 | 
			
		||||
CHECK-NEXT: Dump from Child 14
 | 
			
		||||
CHECK-NEXT: Dump from Child 15
 | 
			
		||||
CHECK-NEXT: Dump from Child 16
 | 
			
		||||
CHECK-NEXT: Dump from Child 17
 | 
			
		||||
CHECK-NEXT: Dump from Child 18
 | 
			
		||||
CHECK-NEXT: Dump from Child 19
 | 
			
		||||
CHECK-NEXT: Dump from Child 20
 | 
			
		||||
CHECK-NEXT: Dump from parent 21
 | 
			
		||||
		Loading…
	
		Reference in New Issue