Mercurial > hg
view contrib/chg/util.c @ 40374:47c03042cd1d
branchmap: pass changelog into branchmap functions
As part of building the branchmap, we loop over revs and call branchmap()
or _branchmap(). Previously, these functions were accessing repo.changelog.
We know from past experience that repo.changelog in loops is bad for
performance.
This commit teaches the branchmap code to pass a changelog instance into
branchmap() and _branchmap() so we don't need to pay this penalty.
On my MBP, this appears to show a speedup on a clone of the
mozilla-unified repo:
$ hg perfbranchmap --clear-revbranch
! base
! wall 21.078160 comb 21.070000 user 20.920000 sys 0.150000 (best of 3)
! wall 20.574682 comb 20.560000 user 20.400000 sys 0.160000 (best of 3)
$ hg perfbranchmap
! base
! wall 4.880413 comb 4.870000 user 4.860000 sys 0.010000 (best of 3)
! wall 4.573968 comb 4.560000 user 4.550000 sys 0.010000 (best of 3)
Differential Revision: https://phab.mercurial-scm.org/D5161
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Fri, 19 Oct 2018 16:16:17 +0200 |
parents | 9724f54923ec |
children | 763b45bc4483 |
line wrap: on
line source
/* * Utility functions * * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org> * * This software may be used and distributed according to the terms of the * GNU General Public License version 2 or any later version. */ #include <errno.h> #include <fcntl.h> #include <signal.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include "util.h" static int colorenabled = 0; static inline void fsetcolor(FILE *fp, const char *code) { if (!colorenabled) return; fprintf(fp, "\033[%sm", code); } static void vabortmsgerrno(int no, const char *fmt, va_list args) { fsetcolor(stderr, "1;31"); fputs("chg: abort: ", stderr); vfprintf(stderr, fmt, args); if (no != 0) fprintf(stderr, " (errno = %d, %s)", no, strerror(no)); fsetcolor(stderr, ""); fputc('\n', stderr); exit(255); } void abortmsg(const char *fmt, ...) { va_list args; va_start(args, fmt); vabortmsgerrno(0, fmt, args); va_end(args); } void abortmsgerrno(const char *fmt, ...) { int no = errno; va_list args; va_start(args, fmt); vabortmsgerrno(no, fmt, args); va_end(args); } static int debugmsgenabled = 0; static double debugstart = 0; static double now() { struct timeval t; gettimeofday(&t, NULL); return t.tv_usec / 1e6 + t.tv_sec; } void enablecolor(void) { colorenabled = 1; } void enabledebugmsg(void) { debugmsgenabled = 1; debugstart = now(); } void debugmsg(const char *fmt, ...) { if (!debugmsgenabled) return; va_list args; va_start(args, fmt); fsetcolor(stderr, "1;30"); fprintf(stderr, "chg: debug: %4.6f ", now() - debugstart); vfprintf(stderr, fmt, args); fsetcolor(stderr, ""); fputc('\n', stderr); va_end(args); } void fchdirx(int dirfd) { int r = fchdir(dirfd); if (r == -1) abortmsgerrno("failed to fchdir"); } void fsetcloexec(int fd) { int flags = fcntl(fd, F_GETFD); if (flags < 0) abortmsgerrno("cannot get flags of fd %d", fd); if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) abortmsgerrno("cannot set flags of fd %d", fd); } void *mallocx(size_t size) { void *result = malloc(size); if (!result) abortmsg("failed to malloc"); return result; } void *reallocx(void *ptr, size_t size) { void *result = realloc(ptr, size); if (!result) abortmsg("failed to realloc"); return result; } /* * Execute a shell command in mostly the same manner as system(), with the * give environment variables, after chdir to the given cwd. Returns a status * code compatible with the Python subprocess module. */ int runshellcmd(const char *cmd, const char *envp[], const char *cwd) { enum { F_SIGINT = 1, F_SIGQUIT = 2, F_SIGMASK = 4, F_WAITPID = 8 }; unsigned int doneflags = 0; int status = 0; struct sigaction newsa, oldsaint, oldsaquit; sigset_t oldmask; /* block or mask signals just as system() does */ memset(&newsa, 0, sizeof(newsa)); newsa.sa_handler = SIG_IGN; newsa.sa_flags = 0; if (sigemptyset(&newsa.sa_mask) < 0) goto done; if (sigaction(SIGINT, &newsa, &oldsaint) < 0) goto done; doneflags |= F_SIGINT; if (sigaction(SIGQUIT, &newsa, &oldsaquit) < 0) goto done; doneflags |= F_SIGQUIT; if (sigaddset(&newsa.sa_mask, SIGCHLD) < 0) goto done; if (sigprocmask(SIG_BLOCK, &newsa.sa_mask, &oldmask) < 0) goto done; doneflags |= F_SIGMASK; pid_t pid = fork(); if (pid < 0) goto done; if (pid == 0) { sigaction(SIGINT, &oldsaint, NULL); sigaction(SIGQUIT, &oldsaquit, NULL); sigprocmask(SIG_SETMASK, &oldmask, NULL); if (cwd && chdir(cwd) < 0) _exit(127); const char *argv[] = {"sh", "-c", cmd, NULL}; if (envp) { execve("/bin/sh", (char **)argv, (char **)envp); } else { execv("/bin/sh", (char **)argv); } _exit(127); } else { if (waitpid(pid, &status, 0) < 0) goto done; doneflags |= F_WAITPID; } done: if (doneflags & F_SIGINT) sigaction(SIGINT, &oldsaint, NULL); if (doneflags & F_SIGQUIT) sigaction(SIGQUIT, &oldsaquit, NULL); if (doneflags & F_SIGMASK) sigprocmask(SIG_SETMASK, &oldmask, NULL); /* no way to report other errors, use 127 (= shell termination) */ if (!(doneflags & F_WAITPID)) return 127; if (WIFEXITED(status)) return WEXITSTATUS(status); if (WIFSIGNALED(status)) return -WTERMSIG(status); return 127; }