I was looking at a flame graph of an ingestion workload with @dliappis, and it looks like we parse the JSON representation of the index request twice when a document has both a pipeline and a final pipeline.

It's hard to know how much we would save on this benchmark since not all data streams in this benchmark had both a pipeline and a final pipeline, but the cost of parsing index request into maps of maps via IngestService represented 4.06% of overall CPU time according to the flame graph, so this might not be negligible.
server/src/test/java/org/elasticsearch/ingest/IngestServiceTests.java
if (finalIndices.size() > 0) {
            assertThat(
                e.getMessage(),
                containsString(
                    String.format(
                        Locale.ROOT,
                        "final pipeline for %s index(es) including [%s]",
                        finalIndices.size(),
                        finalIndices.stream().sorted().limit(3).collect(Collectors.joining(","))
                    )
                )
            );
        }
    }
    public void testGetProcessorsInPipeline() throws Exception {
        IngestService ingestService = createWithProcessors();
        String id = "_id";
        Pipeline pipeline = ingestService.getPipeline(id);
        assertThat(pipeline, nullValue());
        ClusterState clusterState = ClusterState.builder(new ClusterName("_name")).build(); 
        PutPipelineRequest putRequest = new PutPipelineRequest("_id", new BytesArray("""
            {
              "processors": [
                {
                  "set": {
                    "field": "_field",
                    "value": "_value",
                    "tag": "tag1"
                  }
                },