Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eWBYm-00050M-Aa for pgsql-hackers@arkaria.postgresql.org; Tue, 02 Jan 2018 01:40:08 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eWBYk-0003CJ-3j for pgsql-hackers@arkaria.postgresql.org; Tue, 02 Jan 2018 01:40:06 +0000 Received: from makus.postgresql.org ([2001:4800:1501:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1eWBYj-0003C5-CT for pgsql-hackers@lists.postgresql.org; Tue, 02 Jan 2018 01:40:05 +0000 Received: from mail-pf0-x22a.google.com ([2607:f8b0:400e:c00::22a]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1eWBYf-0007vF-PS for pgsql-hackers@postgresql.org; Tue, 02 Jan 2018 01:40:03 +0000 Received: by mail-pf0-x22a.google.com with SMTP id d23so25079349pfe.9 for ; Mon, 01 Jan 2018 17:40:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=leadboat.com; s=google; h=date:from:to:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=UKqYGHQUcnfysBABT0Gehl+lHrl5FO8QPnqPpgxdZUU=; b=HqFwiaZ3ZPN1fd4lp13m41kHV3QDopUt/HqwBlR9IUk0pT2Hwi80CkG+QY2DsJ17C4 CRKIuebuAML4KtC+83+gmEKNBBQkJCVfY4i+I8AKby5PaUvgfhD+KgmLiBoAlerd4kQr Q+RAtN1VT5saY+s3O70svjBYjZoI4Ipxjd9TM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=UKqYGHQUcnfysBABT0Gehl+lHrl5FO8QPnqPpgxdZUU=; b=DVh2l3qGM15h1zRc9n81whT9qwktLnpArSS60biHOFXXlzhaJemXO5mNBD/df+Om9/ YV5HR4aaZxz8O9ECQQFFSAehYcKHrqzyYCiAxiQOQ0N/CYFNySAnbrOqPzy4L8M9jOgR Pe2JC/Tg43RUmSF8FxIZdJKpgMgVrC4XjwqJ9gDkl0DEbhv5/Jv++7dUJjqps0EvKFqi LT+CsLLTGEOyNuLonXSjRyn57R7hZq6vVN8KMpnMCJT3r6ZjQsHjd8zam3n5dNpfKYNA bA5R8bgCUFwU3mjsAtulKk6nBso8SbqIvyRN/cTcqceOue53WrZvPiBryzopxAyyiihb OBjQ== X-Gm-Message-State: AKGB3mITx1JgQRM/daayhxVz+PwyjIoj8m4HgYYtdV1CcQgCoWs9luAI kN74rOeQ70xV5xqNL3HAD4InL+MSS8s= X-Google-Smtp-Source: ACJfBotjKdTKa6B/KFZItbmEbmO8V1kWfBD3h4iLR680NO2T1xYlDiHtLQG1HcryC5ld4tT4D9+wWQ== X-Received: by 10.98.7.27 with SMTP id b27mr37075119pfd.240.1514857199154; Mon, 01 Jan 2018 17:39:59 -0800 (PST) Received: from rfd.leadboat.com (c-73-158-248-138.hsd1.ca.comcast.net. [73.158.248.138]) by smtp.gmail.com with ESMTPSA id p87sm92375787pfi.95.2018.01.01.17.39.57 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 01 Jan 2018 17:39:58 -0800 (PST) Date: Mon, 1 Jan 2018 17:39:56 -0800 From: Noah Misch To: pgsql-hackers@postgresql.org Subject: Re: Race to build pg_isolation_regress in "make -j check-world" Message-ID: <20180102013956.GA898314@rfd.leadboat.com> References: <20171106080752.GA1298146@rfd.leadboat.com> <20171217040605.GA2421254@rfd.leadboat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20171217040605.GA2421254@rfd.leadboat.com> User-Agent: Mutt/1.5.24 (2015-08-30) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk On Sat, Dec 16, 2017 at 08:06:05PM -0800, Noah Misch wrote: > On Mon, Nov 06, 2017 at 12:07:52AM -0800, Noah Misch wrote: > I now see similar trouble from multiple > "make" processes running "make -C contrib/test_decoding install" concurrently. > This is a risk for any directory named in an EXTRA_INSTALL variable of more > than one makefile. Under the right circumstances, this would affect > contrib/hstore and others in addition to contrib/test_decoding. That brings > me back to the locking idea: > > > The problem of multiple "make" processes in a directory (especially src/port) > > shows up elsewhere. In a cleaned tree, "make -j -C src/bin" or "make -j > > installcheck-world" will do it. For more-prominent use cases, src/Makefile > > prevents this with ".NOTPARALLEL:" and building first the directories that are > > frequent submake targets. Perhaps we could fix the general problem with > > directory locking; targets that call "$(MAKE) -C FOO" would first sleep until > > FOO's lock is available. That could be tricky to make robust. > > If one is willing to assume that a lock-holding process never crashes, locking > in a shell script is simple: mkdir to lock, rmdir to unlock. I don't want to > assume that. The bakery algorithm provides convenient opportunities for > checking whether the last locker crashed; I have attached a shell script > demonstrating this approach. Better ideas? Otherwise, I'll look into > integrating this design into the makefiles. Performance has been the principal snare. I value "make -j" being fast when there's little to rebuild, but that shell script approach slowed an empty build by 340% (GNU/Linux w/ SSD) to 2300% (Cygwin). In a build having nothing to do, merely adding a no-op wrapper around "make -C" (does nothing but execvp() the real GNU make) slowed the build by over 10%[1]. To get what I considered decent performance took several design changes: 1. Replace the shell script implementation of the bakery algorithm with a C program that issues fcntl(F_SETLK) on the target directory's makefile. 2. Stop re-entering widely-referenced directories like src/common and src/port dozens of times per build. Instead, enter them before any "make -C", then assume they're built if $(MAKELEVEL) is nonzero. This reduced the total number of "make -C" calls and lock acquisitions from 276 to 147. 3. Lock only directories known to be entered more than once per top-level target. Preliminarily, this reduced the 147 lock acquisitions to 25. I regret that (3) entails ongoing maintenance of a whitelist of such directories; adding a "make -C" call can expand the list. However, I can automate verification of that whitelist. If I abandon (3), an empty build in an NFS-mounted source directory slows from 6.4s to 22s; with all three design changes intact, it slows to 6.6s. I think that justifies keeping (3). I considered abandoning (1). An empty build would then slow from 6.6s to 7.7s on NFS-mounted sources, and it would slow from 2.1s to 6.8s on Cygwin. (I expect similar on MSYS.) That is perhaps acceptable. It would save a few lines of code and perhaps avoid portability snags. Unlike abandoning (3), I would not expect long-term maintenance savings. For systems with low PID entropy[2], (1) also eliminates unreliable code for detecting that a lock holder has died. I plan to keep all three design changes. The non-performance problems that arose were easy to fix: a. In addition to avoiding overlapping "make install" invocations in each directory, we must ensure no directory is installed more than once per tmp_install. Otherwise, the second "make install" could unlink or overwrite a file while another process runs a test that uses the file. I fixed this with stamp files like we use elsewhere in Makefile.global. b. Our "make -C" call graph has cycles[3]. To avoid deadlocks, I accumulated lock-holding PIDs in an environment variable. If the holder of a desired lock appears in that variable, then that holder is sleeping until after the present process completes. We can then proceed without a lock acquisition. Comments? Otherwise, I'll look at finishing the patch series. Thanks, nm [1] I was surprised to see that GNU make is this efficient at determining there's nothing to rebuild. [2] For example, Cygwin reuses PIDs as often as every 645 processes. Also, Cygwin processes have both a Cygwin PID and a Windows PID, and kill() can match either PID. The shell script relied on kill(PID, 0) to deduce that a lock holder had died. We may have ended up needing a secondary factor, like process start time, on such systems. [3] For example, src/backend depends on libpgport_srv.a, and src/port depends on submake-errcodes of src/backend.