private function compareStackTraces()

in prod/php/ElasticOTel/InferredSpans/InferredSpans.php [122:187]


    private function compareStackTraces(array $stackTrace, int $durationMs, bool $topFrameIsInternalFunction, ?int $apmFramesFilteredOut): void
    {
        $this->stackTraceId++;

        $identicalFramesCount = $this->getHowManyStackFramesAreIdenticalFromStackBottom($stackTrace);
        self::logDebug("Same frames count: " . $identicalFramesCount); //, [$stackTrace, $this->lastStackTrace]);

        $lastStackTraceCount = count($this->lastStackTrace);
        $oldFramesCount = $lastStackTraceCount - $identicalFramesCount;

        // on previous stack trace - end all spans above identical frames
        $previousFrameStackTraceId = -1;
        $forceParentChangeFailed = false;

        for ($index = 0; $index < $oldFramesCount; $index++) {
            $endEpochNanos = null;
             // if last frame was internal function, so duration contains it's time, previous ones ended between sampling interval - they're shorter
            if ($topFrameIsInternalFunction) {
                $endEpochNanos = $this->getStartTime($durationMs);
            }

            $dropSpan = false;
            if ($this->spanReductionEnabled) {
                $dropSpan = $this->shouldReduceFrame($index, $oldFramesCount, $previousFrameStackTraceId, $forceParentChangeFailed);
            }

            $this->endFrameSpan($this->lastStackTrace[$index], $dropSpan, $endEpochNanos);

            unset($this->lastStackTrace[$index]); // remove ended frame
        }

        // reindex array
        $this->lastStackTrace = array_values($this->lastStackTrace);

        $stackTraceCount = count($stackTrace);
        if ($stackTraceCount == $identicalFramesCount) {
            // no frames to start
            return;
        }

        $first = true;

        // start spans for all frames below identical frames

        for ($index = $stackTraceCount - $identicalFramesCount - 1; $index >= 0; $index--) {
            if ($first && $apmFramesFilteredOut && !empty($this->lastStackTrace)) {
                self::logDebug("Going to start span in previous span context");
                $newFrame = $this->startFrameSpan($stackTrace[$index], $durationMs, $this->lastStackTrace[0][self::METADATA_CONTEXT]->get(), $this->stackTraceId);
            } else {
                $newFrame = $this->startFrameSpan($stackTrace[$index], $durationMs, null, $this->stackTraceId);
            }

            $first = false;

            if ($this->attachStackTrace) {
                $newFrame[self::METADATA_SPAN]->get()?->setAttribute(TraceAttributes::CODE_STACKTRACE, $this->getStackTrace($this->lastStackTrace));
            }

            if ($index == 0 && $topFrameIsInternalFunction) {
                /** @noinspection PhpRedundantOptionalArgumentInspection */
                $this->endFrameSpan($newFrame, false, null); // we don't need to save the newest internal frame, it ended
            } else {
                array_unshift($this->lastStackTrace, $newFrame); // push-copy frame in front of last stack trace for next interruption processing
            }
        }
    }