static struct startup_info git_startup_info;
  static int use_pager = -1;
- static char orig_cwd[PATH_MAX];
++static char *orig_cwd;
 +static const char *env_names[] = {
 +      GIT_DIR_ENVIRONMENT,
 +      GIT_WORK_TREE_ENVIRONMENT,
 +      GIT_IMPLICIT_WORK_TREE_ENVIRONMENT,
 +      GIT_PREFIX_ENVIRONMENT
 +};
 +static char *orig_env[4];
 +static int saved_environment;
 +
 +static void save_env(void)
 +{
 +      int i;
 +      if (saved_environment)
 +              return;
 +      saved_environment = 1;
-       if (!getcwd(orig_cwd, sizeof(orig_cwd)))
-               die_errno("cannot getcwd");
++      orig_cwd = xgetcwd();
 +      for (i = 0; i < ARRAY_SIZE(env_names); i++) {
 +              orig_env[i] = getenv(env_names[i]);
 +              if (orig_env[i])
 +                      orig_env[i] = xstrdup(orig_env[i]);
 +      }
 +}
 +
 +static void restore_env(void)
 +{
 +      int i;
-       if (*orig_cwd && chdir(orig_cwd))
++      if (orig_cwd && chdir(orig_cwd))
 +              die_errno("could not move to %s", orig_cwd);
++      free(orig_cwd);
 +      for (i = 0; i < ARRAY_SIZE(env_names); i++) {
 +              if (orig_env[i])
 +                      setenv(env_names[i], orig_env[i], 1);
 +              else
 +                      unsetenv(env_names[i]);
 +      }
 +}
  
  static void commit_pager_choice(void) {
        switch (use_pager) {
 
  /* FIXME: move prefix to startup_info struct and get rid of this arg */
  void trace_repo_setup(const char *prefix)
  {
 -      static const char *key = "GIT_TRACE_SETUP";
 +      static struct trace_key key = TRACE_KEY_INIT(SETUP);
        const char *git_work_tree;
-       char cwd[PATH_MAX];
+       char *cwd;
  
 -      if (!trace_want(key))
 +      if (!trace_want(&key))
                return;
  
-       if (!getcwd(cwd, PATH_MAX))
-               die("Unable to get current working directory");
+       cwd = xgetcwd();
  
        if (!(git_work_tree = get_git_work_tree()))
                git_work_tree = "(null)";
        if (!prefix)
                prefix = "(null)";
  
 -      trace_printf_key(key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
 -      trace_printf_key(key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
 -      trace_printf_key(key, "setup: cwd: %s\n", quote_crnl(cwd));
 -      trace_printf_key(key, "setup: prefix: %s\n", quote_crnl(prefix));
 +      trace_printf_key(&key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
 +      trace_printf_key(&key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
 +      trace_printf_key(&key, "setup: cwd: %s\n", quote_crnl(cwd));
 +      trace_printf_key(&key, "setup: prefix: %s\n", quote_crnl(prefix));
+ 
+       free(cwd);
  }
  
 -int trace_want(const char *key)
 +int trace_want(struct trace_key *key)
  {
 -      const char *trace = getenv(key);
 +      return !!get_trace_fd(key);
 +}
  
 -      if (!trace || !strcmp(trace, "") ||
 -          !strcmp(trace, "0") || !strcasecmp(trace, "false"))
 +#ifdef HAVE_CLOCK_GETTIME
 +
 +static inline uint64_t highres_nanos(void)
 +{
 +      struct timespec ts;
 +      if (clock_gettime(CLOCK_MONOTONIC, &ts))
                return 0;
 -      return 1;
 +      return (uint64_t) ts.tv_sec * 1000000000 + ts.tv_nsec;
 +}
 +
 +#elif defined (GIT_WINDOWS_NATIVE)
 +
 +static inline uint64_t highres_nanos(void)
 +{
 +      static uint64_t high_ns, scaled_low_ns;
 +      static int scale;
 +      LARGE_INTEGER cnt;
 +
 +      if (!scale) {
 +              if (!QueryPerformanceFrequency(&cnt))
 +                      return 0;
 +
 +              /* high_ns = number of ns per cnt.HighPart */
 +              high_ns = (1000000000LL << 32) / (uint64_t) cnt.QuadPart;
 +
 +              /*
 +               * Number of ns per cnt.LowPart is 10^9 / frequency (or
 +               * high_ns >> 32). For maximum precision, we scale this factor
 +               * so that it just fits within 32 bit (i.e. won't overflow if
 +               * multiplied with cnt.LowPart).
 +               */
 +              scaled_low_ns = high_ns;
 +              scale = 32;
 +              while (scaled_low_ns >= 0x100000000LL) {
 +                      scaled_low_ns >>= 1;
 +                      scale--;
 +              }
 +      }
 +
 +      /* if QPF worked on initialization, we expect QPC to work as well */
 +      QueryPerformanceCounter(&cnt);
 +
 +      return (high_ns * cnt.HighPart) +
 +             ((scaled_low_ns * cnt.LowPart) >> scale);
 +}
 +
 +#else
 +# define highres_nanos() 0
 +#endif
 +
 +static inline uint64_t gettimeofday_nanos(void)
 +{
 +      struct timeval tv;
 +      gettimeofday(&tv, NULL);
 +      return (uint64_t) tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
 +}
 +
 +/*
 + * Returns nanoseconds since the epoch (01/01/1970), for performance tracing
 + * (i.e. favoring high precision over wall clock time accuracy).
 + */
 +inline uint64_t getnanotime(void)
 +{
 +      static uint64_t offset;
 +      if (offset > 1) {
 +              /* initialization succeeded, return offset + high res time */
 +              return offset + highres_nanos();
 +      } else if (offset == 1) {
 +              /* initialization failed, fall back to gettimeofday */
 +              return gettimeofday_nanos();
 +      } else {
 +              /* initialize offset if high resolution timer works */
 +              uint64_t now = gettimeofday_nanos();
 +              uint64_t highres = highres_nanos();
 +              if (highres)
 +                      offset = now - highres;
 +              else
 +                      offset = 1;
 +              return now;
 +      }
 +}
 +
 +static uint64_t command_start_time;
 +static struct strbuf command_line = STRBUF_INIT;
 +
 +static void print_command_performance_atexit(void)
 +{
 +      trace_performance_since(command_start_time, "git command:%s",
 +                              command_line.buf);
 +}
 +
 +void trace_command_performance(const char **argv)
 +{
 +      if (!trace_want(&trace_perf_key))
 +              return;
 +
 +      if (!command_start_time)
 +              atexit(print_command_performance_atexit);
 +
 +      strbuf_reset(&command_line);
 +      sq_quote_argv(&command_line, argv, 0);
 +      command_start_time = getnanotime();
  }