# `profile` — Pure Python profiler

Source code: Lib/profile.py

Deprecated since version 3.15, will be removed in version 3.17.

The `profile` module is deprecated and will be removed in Python 3.17. Use `profiling.tracing` instead.

The `profile` module provides a pure Python implementation of a deterministic profiler. While useful for understanding profiler internals or extending profiler behavior through subclassing, its pure Python implementation introduces significant overhead compared to the C-based `profiling.tracing` module.

For most profiling tasks, use:

- `profiling.sampling` for production debugging with zero overhead

- `profiling.tracing` for development and testing

## Migration

Migrating from `profile` to `profiling.tracing` is straightforward. The APIs are compatible:

    # Old (deprecated)
    import profile
    profile.run('my_function()')

    # New (recommended)
    import profiling.tracing
    profiling.tracing.run('my_function()')

For most code, replacing `import profile` with `import profiling.tracing` (and using `profiling.tracing` instead of `profile` throughout) provides a straightforward migration path.

참고

The `cProfile` module remains available as a backward-compatible alias to `profiling.tracing`. Existing code using `import cProfile` will continue to work without modification.

## `profile` and `profiling.tracing` module reference

Both the `profile` and `profiling.tracing` modules provide the following functions:

profile.run(command, filename=None, sort=-1)

  이 함수는 `exec()` 함수에 전달할 수 있는 단일 인자와 선택적 파일 이름을 취합니다. 모든 경우에 이 루틴은 다음을 실행합니다:

      exec(command, __main__.__dict__, __main__.__dict__)

  그리고 실행으로부터 프로파일링 통계를 수집합니다. 파일 이름이 없으면, 이 함수는 자동으로 `Stats` 인스턴스를 만들고 간단한 프로파일링 보고서를 인쇄합니다. 정렬 값이 지정되면, 이 `Stats` 인스턴스로 전달되어 결과 정렬 방법을 제어합니다.

profile.runctx(command, globals, locals, filename=None, sort=-1)

  이 함수는 `run()`과 유사하며, command 문자열에 대한 전역(globals)과 지역(locals) 매핑 제공하기 위한 인자가 추가되었습니다. 이 루틴은 다음을 실행합니다:

      exec(command, globals, locals)

  그리고 위의 `run()` 함수에서와같이 프로파일링 통계를 수집합니다.

class profile.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)

  This class is normally only used if more precise control over profiling is needed than what the `profiling.tracing.run()` function provides.

  timer 인자를 통해 코드를 실행하는 데 걸리는 시간을 측정하기 위한 사용자 정의 타이머를 제공할 수 있습니다. 현재 시각을 나타내는 단일 숫자를 반환하는 함수여야 합니다. 숫자가 정수이면, timeunit는 각 시간 단위의 지속 시간을 지정하는 승수를 지정합니다. 예를 들어, 타이머가 밀리초 단위로 측정된 시간을 반환하면 시간 단위는 `.001`입니다.

  `Profile` 클래스를 직접 사용하면 프로파일 데이터를 파일에 쓰지 않고도 프로파일 결과를 포맷할 수 있습니다:

      import profiling.tracing
      import pstats
      import io
      from pstats import SortKey

      pr = profiling.tracing.Profile()
      pr.enable()
      # ... do something ...
      pr.disable()
      s = io.StringIO()
      sortby = SortKey.CUMULATIVE
      ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
      ps.print_stats()
      print(s.getvalue())

  The `Profile` class can also be used as a context manager (supported only in `profiling.tracing`, not in the deprecated `profile` module; see 컨텍스트 관리자 형):

      import profiling.tracing

      with profiling.tracing.Profile() as pr:
          # ... do something ...

          pr.print_stats()

  버전 3.8에서 변경: 컨텍스트 관리자 지원이 추가되었습니다.

  enable()

    Start collecting profiling data. Only in `profiling.tracing`.

  disable()

    Stop collecting profiling data. Only in `profiling.tracing`.

  create_stats()

    프로파일링 데이터 수집을 중지하고 결과를 내부적으로 현재 프로파일로 기록합니다.

  print_stats(sort=-1)

    현재 프로파일을 기반으로 `Stats` 객체를 만들고 결과를 stdout에 인쇄합니다.

    The sort parameter specifies the sorting order of the displayed statistics. It accepts a single key or a tuple of keys to enable multi-level sorting, as in `pstats.Stats.sort_stats()`.

    Added in version 3.13: `print_stats()` now accepts a tuple of keys.

  dump_stats(filename)

    현재 프로파일의 결과를 filename에 씁니다.

  run(cmd)

    `exec()`를 통해 cmd를 프로파일 합니다.

  runctx(cmd, globals, locals)

    지정된 전역과 지역 환경으로 `exec()`를 통해 cmd를 프로파일 합니다.

  runcall(func, /, *args, **kwargs)

    `func(*args, **kwargs)`를 프로파일 합니다

프로파일링은 호출된 명령/함수가 실제로 반환하는 경우에만 작동함에 유의하십시오. 인터프리터가 종료되면 (예를 들어 호출된 명령/함수 실행 중 `sys.exit()` 호출을 통해) 아무런 프로파일링 결과도 인쇄되지 않습니다.

## Differences from `profiling.tracing`

The `profile` module differs from `profiling.tracing` in several ways:

Higher overhead. The pure Python implementation is significantly slower than the C implementation, making it unsuitable for profiling long-running programs or performance-sensitive code.

Calibration support. The `profile` module supports calibration to compensate for profiling overhead. This is not needed in `profiling.tracing` because the C implementation has negligible overhead.

Custom timers. Both modules support custom timers, but `profile` accepts timer functions that return tuples (like `os.times()`), while `profiling.tracing` requires a function returning a single number.

Subclassing. The pure Python implementation is easier to subclass and extend for custom profiling behavior.

## What is deterministic profiling?

Deterministic profiling is meant to reflect the fact that all function call, function return, and exception events are monitored, and precise timings are made for the intervals between these events (during which time the user’s code is executing). In contrast, statistical profiling (which is provided by the `profiling.sampling` module) periodically samples the effective instruction pointer, and deduces where time is being spent. The latter technique traditionally involves less overhead (as the code does not need to be instrumented), but provides only relative indications of where time is being spent.

파이썬에서는, 실행 중에 인터프리터가 활성화되어있어서, 결정론적 프로파일링을 수행하기 위해 인스트루먼트 된 코드(instrumented code)가 필요하지 않습니다. 파이썬은 각 이벤트에 대해 자동으로 훅(hook)(선택적 콜백)을 제공합니다. 또한, 파이썬의 인터프리터 적인 성격은 실행에 이미 많은 오버헤드를 추가하는 경향이 있어서, 결정론적 프로파일링은 일반적인 응용 프로그램에서 작은 처리 오버헤드만 추가하는 경향이 있습니다. 결과적으로 결정론적 프로파일링은 그다지 비싸지 않으면서도, 파이썬 프로그램의 실행에 대한 광범위한 실행 시간 통계를 제공합니다.

호출 수 통계를 사용하여 코드의 버그(놀랄만한 횟수)를 식별하고, 가능한 인라인 확장 지점(높은 호출 횟수)을 식별할 수 있습니다. 내부 시간 통계를 사용하여 신중하게 최적화해야 하는 “핫 루프(hot loops)”를 식별할 수 있습니다. 누적 시간 통계를 사용하여 알고리즘 선택에서의 고수준 에러를 식별할 수 있습니다. 이 프로파일러에서의 누적 시간의 특이한 처리는 알고리즘의 재귀 구현에 대한 통계를 반복 구현과 직접 비교할 수 있도록 함에 유의하십시오.

## 한계

타이밍 정보의 정확성과 관련하여 한 가지 제약이 있습니다. 정확성과 관련해서는 결정론적 프로파일러에 근본적인 문제가 있습니다. 가장 명백한 제약은 하부 “시계”가 (일반적으로) 약 .001 초의 속도로만 눈금이 변하는 것입니다. 따라서 하부 시계보다 더 정확한 측정은 없습니다. 충분한 측정을 수행하면, “에러”가 평균이 되어 사라지는 경향이 있습니다. 불행히도, 이 첫 번째 에러를 제거하면 두 번째 에러 원인이 발생합니다.

두 번째 문제는 이벤트가 디스패치 된 시점부터 프로파일러가 시간을 얻기 위해 호출하는 것이 실제로 시계의 상태를 얻기까지 “시간이 걸린다”는 것입니다. 마찬가지로, 프로파일러 이벤트 핸들러를 빠져나갈 때 시계값이 획득된 (그런 다음 저장됩니다) 시간부터, 사용자의 코드가 다시 실행될 때까지 어떤 지연이 발생합니다. 결과적으로, 여러 번 호출되거나, 많은 함수를 호출하는 함수는 일반적으로 이 에러를 누적합니다. 이러한 방식으로 누적되는 에러는 일반적으로 시계 정확도(1 눈금 미만)보다 작지만, 누적될 수 있어서 매우 중요해집니다.

The problem is more important with the deprecated `profile` module than with the lower-overhead `profiling.tracing`. For this reason, `profile` provides a means of calibrating itself for a given platform so that this error can be probabilistically (on the average) removed. After the profiler is calibrated, it will be more accurate (in a least square sense), but it will sometimes produce negative numbers (when call counts are exceptionally low, and the gods of probability work against you :-). ) Do not be alarmed by negative numbers in the profile. They should only appear if you have calibrated your profiler, and the results are actually better than without calibration.

## 보정

`profile` 모듈의 프로파일러는 각 이벤트 처리 시간에서 상수를 빼서 시간 함수 호출의 오버헤드를 보상하고, 결과를 잘 보관합니다. 기본적으로, 상수는 0입니다. 다음 절차는 주어진 플랫폼에 대해 더 나은 상수를 얻는 데 사용될 수 있습니다 (한계를 참조하십시오).

    import profile
    pr = profile.Profile()
    for i in range(5):
        print(pr.calibrate(10000))

이 메서드는 인자가 제공한 횟수의 파이썬 호출을, 직접하고 프로파일러하에서 다시 하면서, 두 두 시간을 측정합니다. 그런 다음 프로파일러 이벤트 당 숨겨진 오버헤드를 계산하여 부동 소수점으로 반환합니다. 예를 들어, 맥 OS를 실행하는 1.8Ghz 인텔 코어 i5에서, 그리고 파이썬의 time.process_time()을 타이머로 사용할 때, 매직 넘버는 약 4.04e-6입니다.

이 반복의 목적은 상당히 일관된 결과를 얻는 것입니다. 컴퓨터가 매우 빠르거나, 타이머 함수의 해상도가 좋지 않으면, 일관된 결과를 얻기 위해 100000이나 심지어 1000000을 전달해야 할 수 있습니다.

일관된 대답을 얻었을 때, 세 가지 방법으로 사용할 수 있습니다:

    import profile

    # 1. 이후에 만들어지는 모든 Profile 인스턴스에 계산된 바이어스를 적용합니다.
    profile.Profile.bias = your_computed_bias

    # 2. 특정 Profile 인스턴스에 계산된 바이어스를 적용합니다.
    pr = profile.Profile()
    pr.bias = your_computed_bias

    # 3. 인스턴스 생성자에 계산된 바이어스를 지정합니다.
    pr = profile.Profile(bias=your_computed_bias)

선택해야 한다면, 더 작은 상수를 선택하는 것이 좋습니다, 그러면 결과가 프로파일 통계에서 결과가 “덜 자주” 음수로 표시됩니다.

## 사용자 정의 타이머 사용하기

현재 시각을 결정하는 방법을 변경하려면 (예를 들어, 벽시계 시간이나 소요된 프로세스 시간을 사용하도록 만들려면), `Profile` 클래스 생성자에게 원하는 타이밍 함수를 전달합니다:

    pr = profile.Profile(your_time_func)

The resulting profiler will then call `your_time_func`. Depending on whether you are using `profile.Profile` or `profiling.tracing.Profile`, `your_time_func`’s return value will be interpreted differently:

`profile.Profile`

  `your_time_func`는 단일 숫자를 반환하거나, 또는 (`os.times()`가 반환하는 것과 같이) 합계가 현재 시각인 숫자 리스트를 반환해야 합니다. 함수가 단일 시간 숫자를 반환하거나, 반환된 숫자의 리스트 길이가 2이면, 특히 빠른 버전의 디스패치 루틴을 얻게 됩니다.

  여러분이 선택한 타이머 함수에 대해 프로파일러 클래스를 보정해야 합니다 (보정을 참조하십시오). 대부분의 기계에서, 단일 정숫값을 반환하는 타이머는 프로파일링 중 낮은 오버헤드 측면에서 최상의 결과를 제공합니다. (`os.times()`는 부동 소수점 값의 튜플을 반환하므로 꽤 나쁩니다). 더 좋은 타이머를 가장 깨끗한 방식으로 대체하려면, 클래스를 파생하고 적절한 보정 상수와 함께 타이머 호출을 가장 잘 처리하는 대체 디스패치 메서드를 배선하십시오.

`profiling.tracing.Profile`

  `your_time_func`는 단일 숫자를 반환해야 합니다. 정수를 반환하면, 시간 단위의 실제 지속 시간을 지정하는 두 번째 인자로 클래스 생성자를 호출할 수도 있습니다. 예를 들어, `your_integer_time_func`가 밀리초 단위로 측정된 시간을 반환하면, 다음과 같이 `Profile` 인스턴스를 구성합니다:

      pr = profiling.tracing.Profile(your_integer_time_func, 0.001)

  As the `profiling.tracing.Profile` class cannot be calibrated, custom timer functions should be used with care and should be as fast as possible. For the best results with a custom timer, it might be necessary to hard-code it in the C source of the internal `_lsprof` module.

파이썬 3.3은 `time`에 프로세스나 벽시계 시간을 정확하게 측정하는 데 사용할 수 있는 몇 가지 새로운 함수를 추가합니다. 예를 들어, `time.perf_counter()`를 참조하십시오.

더 보기

`profiling`

  Overview of Python profiling tools.

`profiling.tracing`

  Recommended replacement for this module.

`pstats`

  Statistical analysis and formatting for profile data.