Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Benchmark with disabled GIL build and -Xgil=1 isn't enabling GIL #187

Closed
tonybaloney opened this issue May 10, 2024 · 8 comments
Closed
Assignees

Comments

@tonybaloney
Copy link

It seems that when you run PYTHON_GIL=1 python benchmark.py the benchmarked functions are being run with the GIL disabled and ignoring the flag.

Benchmark Code

import pyperf
from multiprocessing import Process
from threading import Thread
try:
    import _xxsubinterpreters as interpreters
except ImportError:
    import _interpreters as interpreters

import itertools

DEFAULT_DIGITS = 2000
icount = itertools.count
islice = itertools.islice

def gen_x():
    return map(lambda k: (k, 4 * k + 2, 0, 2 * k + 1), icount(1))


def compose(a, b):
    aq, ar, as_, at = a
    bq, br, bs, bt = b
    return (aq * bq,
            aq * br + ar * bt,
            as_ * bq + at * bs,
            as_ * br + at * bt)


def extract(z, j):
    q, r, s, t = z
    return (q * j + r) // (s * j + t)


def gen_pi_digits():
    z = (1, 0, 0, 1)
    x = gen_x()
    while 1:
        y = extract(z, 3)
        while y != extract(z, 4):
            z = compose(z, next(x))
            y = extract(z, 3)
        z = compose((10, -10 * y, 0, 1), z)
        yield y


def calc_ndigits(n=DEFAULT_DIGITS):
    return list(islice(gen_pi_digits(), n))

test ="""
import itertools

DEFAULT_DIGITS = 2000
icount = itertools.count
islice = itertools.islice

def gen_x():
    return map(lambda k: (k, 4 * k + 2, 0, 2 * k + 1), icount(1))


def compose(a, b):
    aq, ar, as_, at = a
    bq, br, bs, bt = b
    return (aq * bq,
            aq * br + ar * bt,
            as_ * bq + at * bs,
            as_ * br + at * bt)


def extract(z, j):
    q, r, s, t = z
    return (q * j + r) // (s * j + t)


def gen_pi_digits():
    z = (1, 0, 0, 1)
    x = gen_x()
    while 1:
        y = extract(z, 3)
        while y != extract(z, 4):
            z = compose(z, next(x))
            y = extract(z, 3)
        z = compose((10, -10 * y, 0, 1), z)
        yield y


def calc_ndigits(n=DEFAULT_DIGITS):
    return list(islice(gen_pi_digits(), n))
calc_ndigits()
"""

def bench_threading(n):
    # Code to launch specific model
    threads = []
    for _ in range(n):
        t = Thread(target=calc_ndigits)
        t.start()
        threads.append(t)
    for thread in threads:
        thread.join()

def bench_subinterpreters(n, site=True):
    # Code to launch specific model
    def _spawn_sub():
        sid = interpreters.create()
        interpreters.run_string(sid, test)
        interpreters.destroy(sid)

    threads = []
    for _ in range(n):
        t = Thread(target=_spawn_sub)
        t.start()
        threads.append(t)
    for thread in threads:
        thread.join()

def bench_multiprocessing(n):
    # Code to launch specific model
    processes = []
    for _ in range(n):
        t = Process(target=calc_ndigits)
        t.start()
        processes.append(t)
    for process in processes:
        process.join()

if __name__ == "__main__":
    runner = pyperf.Runner()
    runner.metadata['description'] = "Benchmark execution models"
    n = 10
    runner.bench_func('threading', bench_threading, n)
    runner.bench_func('subinterpreters', bench_subinterpreters, n)
    runner.bench_func('multiprocessing', bench_multiprocessing, n)

Results when running a CPython without --disable-gil:

output_gil1_compiled

Running the benchmark with PYTHON_GIL=0:

output_gil0

Running the benchmark with a no-gil build, but PYTHON_GIL=1 uses all 4 CPU cores and gives the fastest result (faster than PYTHON_GIL=0) which is wrong--

output_gil1

@tonybaloney
Copy link
Author

From python/cpython#118874

@tonybaloney tonybaloney changed the title Benchmark with disable GIL isn't disabling the GIL Benchmark with disabled GIL build and -Xgil=1 isn't enabling GIL May 10, 2024
@tonybaloney
Copy link
Author

@corona10 I saw some mentions from you in the backlog on this topic

@corona10 corona10 self-assigned this May 10, 2024
@corona10
Copy link
Member

corona10 commented May 10, 2024

Okay this should be fixed, since I am busy before PyCon US, if you want to submit the patch before, you can send it :)
Or I will take a look at it during the PyCon US.

@colesbury
Copy link

I'd suggest looking at:

copy_env = ["PATH", "PYTHONPATH", "HOME", "TEMP", "COMSPEC", "SystemRoot", "SystemDrive"]

IIRC, pyperf prevents workers from inheriting environment variables by default, which I've always found more confusing than helpful.

-Xgil is probably also not propagated.

@corona10
Copy link
Member

Yeah today, I am working on.

@tonybaloney
Copy link
Author

@corona10 there is no rush from me. I just wanted to report the issue

corona10 added a commit that referenced this issue May 13, 2024
…188)

* gh-187: Support environment variables PYTHON_GIL / PYTHON_CPU_COUNT

* Update

* Update CI

* update

* Update

* Address code review

* Address code review

* Revert CI file
@mdboom
Copy link
Collaborator

mdboom commented Jul 26, 2024

@tonybaloney: Should this be closed as fixed?

@corona10
Copy link
Member

I think that we can close the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants