Perses: Syntax-Directed Program Reduction

August 20, 2026 · View on GitHub

CI

Perses: Syntax-Directed Program Reduction

Perses is a language-agnostic program reducer to minimize a program with respect to a set of constraints. It takes as input a program to reduce, and a test script which specifies the constraints. It outputs a minimized program which still satisfies the constraints specified in the test script. Compared to Delta Debugging and Hierarchical Delta Debugging, Perses leverages the syntax information in the Antlr grammar, and prunes the search space by avoiding generating syntactically invalid programs.

Supported Languages

Currently, Perses supports reduction for the following programming languages:

  • c: *.c
  • cpp: *.cc, *.cpp, *.cxx
  • glsl: *.glsl, *.comp, *.frag, *.vert
  • go: *.go
  • jackson-yaml: *.jackson, *.yaml, *.yml
  • java: *.java
  • javascript: *.javascript, *.js
  • line: *.line
  • makefile: *.mk
  • mysql: *.mysql
  • onetoken: *.onetoken
  • php: *.php
  • python3: *.py, *.py3
  • ruby: *.rb
  • rust: *.rs
  • scala: *.scala, *.sc
  • smtlibv2: *.smt2, *.sy
  • solidity: *.sol
  • sqlite: *.sqlite
  • system_verilog: *.v, *.sv
  • web assembly: *.wat, *.wasm
  • xml: *.xml

Support for other languages is coming soon.

Obtain and Run

There are three ways to obtain Perses.

  • Download a prebuilt release JAR file from our release page, for example,

    wget https://github.com/uw-pluverse/perses/releases/download/v2.6/perses_deploy.jar
    java -jar perses_deploy.jar [options]? --test-script <test-script.sh> --input-file <program file>
    
  • Clone the repo and build Perses from the source.

    git clone https://github.com/perses-project/perses.git
    cd perses
    bazelisk build //src/org/perses:perses_deploy.jar
    java -jar bazel-bin/src/org/perses/perses_deploy.jar [options]? \
        --test-script <test-script.sh> --input-file <program file>
    
  • If you want to always use the trunk version of Perses, perses-trunk automatically downloads and builds the latest version.

    NOTE: Bazelisk is the prerequisite to run perses-trunk successfully.

    wget https://raw.githubusercontent.com/perses-project/perses/master/scripts/perses-trunk
    chmod +x perses-trunk
    ./perses-trunk [options]? --test-script <test-script.sh> --input-file <program file>
    

Important Flags

  • --test-script <test-script.sh>: The script encodes the constraints that both of the original program file and the reduced version should satisfy. It should return 0 if the constraints are satisfied.

  • --input-file <program-file>: the program needs to be reduced. Currently, Perses supports C, Rust, Java and Go. Note that we can easily support any other languages, if the specific language can be parsed by an Antlr parser.

Writing a Robust Test Script

The test script is the oracle that drives the entire reduction: Perses copies the current candidate program into a fresh working directory, runs the script there, and keeps the candidate only if the script exits 0 (the property of interest still holds); otherwise the candidate is discarded. The script must be deterministic and self-contained — read the program from the working directory (not an absolute path), avoid side effects outside that directory (or use temp directories and then clean them up), and never block on interactive input. Reduced variants routinely provoke compiler crashes, infinite loops, and runaway memory, so the script must defend against a single candidate hanging the whole run.

Guard every external tool with a wall-clock timeout (e.g. timeout -s KILL 10 cc small.c) so no single invocation can run forever. This alone is not enough, though: timeout signals only the process it launches, not that process's descendants. Compiler drivers such as gcc (which forks cc1) or ccomp spawn the real worker as a child, and when the driver is killed that worker is orphaned to init/systemd and can keep spinning at 100% CPU indefinitely — leaking one runaway per bad variant until the machine is starved (dead-but-unreaped descendants pile up as zombies). To close this gap, also set a per-process CPU cap with ulimit -t <seconds> near the top of the script: unlike timeout, RLIMIT_CPU is inherited by every descendant and enforced by the kernel regardless of reparenting, so orphaned runaways are reaped automatically. Pick the cap above the largest per-tool timeout$ (\text{roughly} 2 \times ) \text{so} \text{legitimate} \text{runs} \text{finish} \text{while} \text{runaways} \text{die}, \text{and} \text{optionally} \text{add} $ulimit -v to bound memory. One last caveat: if a timed-out tool's output feeds a pipe or $(...), the shell can still block waiting for EOF because a leaked descendant keeps the pipe's write end open — redirect tool output to a file rather than a pipe when in doubt.

#!/bin/bash
# CPU-time cap in seconds, inherited by every descendant: an orphaned compiler
# that escaped `timeout` is still reaped by the kernel via RLIMIT_CPU.
ulimit -t 20
# Wall-clock guard on each tool; -s KILL force-kills a wedged process. Redirect to
# a file (not a pipe) so a leaked descendant cannot stall the script on EOF.
timeout -s KILL 10 clang -O2 -c small.c > log.txt 2>&1
grep -q "internal compiler error" log.txt && exit 0   # property holds
exit 1                                                 # property broken

Live Web Dashboard

Perses can serve a live web dashboard that visualizes a reduction as it runs: the shrinking token count, the average reduction speed over time, per-reducer statistics, and the history of reducer invocations (the same statistics Perses prints at the end of a run, but updated in real time).

Enable it with --enable-web-ui true. Perses prints a http://127.0.0.1:<port> URL to open in a browser. Use --web-ui-port <port> to pick the port (default 9000; if it is already in use, an ephemeral port is chosen and the actual URL is printed).

java -jar perses_deploy.jar --enable-web-ui true \
    --test-script <test-script.sh> --input-file <program file>

The dashboard binds to localhost only. To watch a reduction that is running on a remote machine, forward the port over SSH, e.g. ssh -L 9000:127.0.0.1:9000 <remote-host>, then open http://127.0.0.1:9000 locally.

Perses live web dashboard

Check all available command line arguments

java -jar perses_deploy.jar  --help

The following is the complete list of command line arguments.

Usage: org.perses.Main [options]

[Outputs]  Options:
    --output-dir, -o
      The output directory to save the reduced result.

[Inputs]  Options:
  * --test-script, --test, -t
      The test script to specify the property the reducer needs to preserve.
  * --input-file, --input, -i
      The input file(s) or directory(ies) to reduce. Repeat the flag to pass 
      multiple, e.g. --input a.c --input b.c, or --input src_dir. A directory 
      is expanded recursively to all regular files under it (the test script 
      and any --deps files are excluded).
      Default: []
    --deps
      The dependency file(s) or directory(ies) required for running the 
      property test. A directory is expanded recursively to all regular files 
      under it.
      Default: []

[General Reduction Control]  Options:
    --global-fixpoint
      iterative reduction till fixpoint, globally
      Default: false
    --fixpoint
      iterative reduction till fixpoint, for the main reducer only
      Default: true
    --threads
      Number of reduction threads: a positive integer, or 'auto'.
      Default: auto
    --code-format
      The format of the reduced program.
      Possible Values: [SINGLE_TOKEN_PER_LINE, ORIG_FORMAT, COMPACT_ORIG_FORMAT, PYTHON3_FORMAT, COMPACT_PYTHON3_FORMAT, YAML_FORMAT]
    --script-execution-timeout-in-seconds
      the interval in seconds to timeout the test script executions. the 
      default timeout is 600 seconds.
      Default: 600
    --script-execution-keep-waiting-after-timeout
      keep trying even after the script execution timeouts.
      Default: true

[Output Refining Control]  Options:
    --call-formatter
      call a formatter on the final result
      Default: false
    --format-cmd
      the command to format the reduced source file
      Default: <empty string>
    --call-creduce
      call C-Reduce when Perses is done.
      Default: false
    --creduce-cmd
      the C-Reduce command name or path
      Default: creduce

[Reduction Algorithm Control]  Options:
    --alg
      The main reduction algorithm: use --list-algs to list all available 
      algorithms 
    --cleanup-alg
      The cleanup reduction algorithm, which is the non-first reduction 
      algorithm used in the fixpoint iteration. Use --list-algs to list all 
      available algorithms.
    --list-algs
      list all the reduction algorithms.
    --reparse-each-iteration
      Reparse the program before the start of each fixpoint iteration.
      Default: true
    --enable-token-slicer
      Enable token slicer after syntax-guided reduction is done. Maybe slow.
      Default: false
    --enable-tree-slicer
      Enable tree slicer after syntax-guided reduction, and before token 
      slicer 
      Default: false
    --line-slicer
      whether to run the line slicer (after syntax-guided reduction, before 
      the token slicer): auto (only for files that do not parse under their 
      real grammar), on (every file), or off
      Default: AUTO
      Possible Values: [AUTO, ON, OFF]
    --min-slicing-window-size
      The minimum window size of the windowed slicer.
      Default: 1
    --max-slicing-window-size
      The maximum window size of the windowed slicer.
      Default: 14

[Language Control]  Options:
    --list-langs
      List all the supported languages.
    --lang
      Specify the language of the program that is to be reduced.
      Default: <empty string>
    --parser-facade-class-name
      The parser facade to be used to parse the input program
      Default: <empty string>
    --list-parser-facades
      List all the available parser facades.
    --language-ext-jars
      A list of JAR files to support new languages
      Default: []

[Classical Perses Reducer Control]  Options:
    --default-list-minimizer-for-kleene
      The default list minimizer algorithm to reduce kleene nodes.
      Default: DFS
      Possible Values: [PRISTINE_DDMIN, PERSES_VARIANT_OF_PRISTINE, DFS, BFS, CDD, WEIGHTED_DFS, WEIGHTED_BFS, PROBDD, WDD, WPROBDD, WINDOWED_SLICER, LOCAL_EXHAUSTIVE_PATTERN_ENUMERATION, ONE_BY_ONE, ADAPTIVE_GAIN_DRIVEN]

[Vulcan Reducer Control]  Options:
    --enable-vulcan
      Enable vulcan (using auxiliary reducers to help produce smaller 
      reduction output).
      Default: false
    --non-deletion-iteration-limit
      The maximum number of continuous non-deletion iterations allowed.
      Default: 10
    --window-size
      The window size used to perform local exhaustive pattern reduction.
      Default: 4
    --vulcan-fixpoint
      Enable vulcan fixpoint iteratively using auxiliary reducers until no 
      progress can be made
      Default: false

[T-Rec Reducer Control]  Options:
    --enable-trec
      enable T-Rec (a lexical-syntax guided fine-grained reduction process to 
      reduce and canonicalize each token)
      Default: true

[Profiling]  Options:
    --progress-dump-file
      The file to record the reduction process. The dump file can be large..
    --actionset-effect-profile
      The file to profile the effect of edit action sets.
    --stat-dump-file
      The file to save the statistics collected during reduction.
    --profile-query-cache-time
      The file to save the profiling data of the query cache.
    --profile-query-cache-time-csv
      The file to save the profiling data of the query cache in the CSV 
      format. 
    --profile-query-cache-memory
      The file to save the profiling data of the query cache.
    --profile-actionset
      The file to save information of all the created edit action sets.
    --profile-list-minimizer
      The file to save the reduction process of the list minimizer.
    --profile-program-size-trend
      The file to save the the size of the program being reduced over time.
    --profile-for-reduction-progress-differential-analysis
      The file to save the reduction process for offline differential 
      analysis. 
    --enable-web-ui
      Serve a live web dashboard of the reduction progress on localhost.
      Default: false
    --web-ui-port
      Preferred port for --enable-web-ui. Falls back to an ephemeral port if 
      taken. 
      Default: 9000

[Cache Control]  Options:
    --query-caching
      Enable query caching for test script executions.
      Default: true
    --default-sha-alg-type
      The SHA algorithm used in the reduction process
      Default: SHA256
      Possible Values: [SHA512, SHA256]

[List Minimizer Microbenchmarking]  Options:
    --list-minimizer-microbenchmarking-mode
      RECORD captures each list minimization problem encountered. EVALUATE 
      runs one minimizer against one recorded problem and reports its cost and 
      result. Unset (the default) runs a normal reduction.
      Possible Values: [RECORD, EVALUATE]
    --list-minimizer-microbenchmark-output
      RECORD: the directory to write recorded microbenchmarks to, one folder 
      each. 
    --min-list-size-to-record
      RECORD: skip problems whose list is shorter than this. Lists of one or 
      two elements leave a minimizer no room to differ, so they say nothing 
      about which one to prefer.
      Default: 6
    --max-microbenchmarks-to-record
      RECORD: stop recording after this many microbenchmarks. Unset means no 
      bound. 
    --evaluation-microbenchmark
      EVALUATE: the microbenchmark.yaml of the recorded problem to evaluate.
    --evaluation-minimizer
      EVALUATE: the list minimizer to evaluate. Exactly one per invocation.
      Possible Values: [PRISTINE_DDMIN, PERSES_VARIANT_OF_PRISTINE, DFS, BFS, CDD, WEIGHTED_DFS, WEIGHTED_BFS, PROBDD, WDD, WPROBDD, WINDOWED_SLICER, LOCAL_EXHAUSTIVE_PATTERN_ENUMERATION, ONE_BY_ONE, ADAPTIVE_GAIN_DRIVEN]
    --evaluation-output
      EVALUATE: the directory to write the metrics CSVs to.

[Experiment Control]  Options:
    --keep-reduction-history
      keep all the reduction folders generated during reduction
      Default: false
    --enable-error-tolerant-grammar
      when a file does not parse under its real grammar, first try an 
      error-tolerant parse of that grammar (keeping its structure, with 
      unparseable fragments as leaf tokens) before falling back to the 
      Dyck/Line tolerant grammars
      Default: true
    --dyck-node-reducer
      whether to run the Dyck node reducer as an extra pass that reparses each 
      file under a Dyck grammar and deletes balanced delimiter groups the real 
      grammar cannot place: auto (only for files that do not parse under their 
      real grammar), on (every file), or off
      Default: AUTO
      Possible Values: [AUTO, ON, OFF]

[LPR Reducer Control]  Options:
    --enable-lpr
      Enable LPR (LLM-based transformations to improve reduction results).
      Default: false
    --lpr-fixpoint
      Enable lpr fixpoint. Everytime a transformation makes progress, go to 
      the next transformation.
      Default: false
    --llm-client-script
      The executable script used to invoke the LLM during LPR. It receives a 
      JSON request (via --input-file) and writes a JSON array of response 
      strings (via --output-file). If omitted, LPR falls back to a bundled 
      default client (lpr/scripts/llm_client.py): an OpenAI-compatible client 
      that by default targets a local ollama server at 
      http://localhost:11434/v1 with model codellama:13b. The fallback is 
      reported in the reduction output when it is used.

[Latra Reducer Control]  Options:
    --enable-latra
      Enable Latra (language-specific transformations to produce smaller 
      reduction output).
      Default: true
    --latra-fixpoint
      Enable fixpoint mode for running Latra reducers.
      Default: true
    --latra-transformation-list-minimizer
      The list minimizer algorithm to reduce with the found transformations
      Default: WPROBDD
      Possible Values: [PRISTINE_DDMIN, PERSES_VARIANT_OF_PRISTINE, DFS, BFS, CDD, WEIGHTED_DFS, WEIGHTED_BFS, PROBDD, WDD, WPROBDD, WINDOWED_SLICER, LOCAL_EXHAUSTIVE_PATTERN_ENUMERATION, ONE_BY_ONE, ADAPTIVE_GAIN_DRIVEN]

[Verbosity]  Options:
    --verbosity
      verbosity of logging
      Default: INFO
    --list-verbosity-levels
      list all verbosity levels
    --hide-timestamps
      hide the timestamps in the log messages
      Default: false

[Version]  Options:
    --version
      print the version

[Help]  Options:
    -h, --help
      print help message

License

GNU General Public License 3.

Publication

This repository contains the implementations of the techniques proposed in the following papers.

1. Perses: Syntax-Guided Program Reduction (ICSE 2018, pdf)

@inproceedings{perses,
  author = {Sun, Chengnian and Li, Yuanbo and Zhang, Qirun and Gu, Tianxiao and Su, Zhendong},
  title = {Perses: Syntax-Guided Program Reduction},
  year = {2018},
  publisher = {Association for Computing Machinery},
  doi = {10.1145/3180155.3180236},
  booktitle = {Proceedings of the 40th International Conference on Software Engineering},
  pages = {361–371},
}

2. Pushing the Limit of 1-Minimality of Language-Agnostic Program Reduction (OOPSLA 2023, pdf)

@article{perses-vulcan,
  title={Pushing the Limit of 1-Minimality of Language-Agnostic Program Reduction},
  author={Xu, Zhenyang and Tian, Yongqiang and Zhang, Mengxiao and Zhao, Gaosen and Jiang, Yu and Sun, Chengnian},
  journal={Proceedings of the ACM on Programming Languages},
  volume={7},
  number={OOPSLA1},
  pages={636--664},
  year={2023},
  publisher={ACM New York, NY, USA}
}

3. PPR: Pairwise Program Reduction (ESEC/FSE 2023, pdf, doc)

@inproceedings{perses-ppr,
  title={PPR: Pairwise Program Reduction},
  author={Zhang, Mengxiao and Xu, Zhenyang and Tian, Yongqiang and Jiang, Yu and Sun, Chengnian},
  booktitle={Proceedings of the 31st ACM Joint European Software Engineering Conference and Symposium on the Foundations of Software Engineering},
  pages={338--349},
  year={2023}
}

4. Ad Hoc Syntax-Guided Program Reduction (ESEC/FSE Tool 2023, pdf)

@inproceedings{10.1145/3611643.3613101,
  author = {Tian, Jia Le and Zhang, Mengxiao and Xu, Zhenyang and Tian, Yongqiang and Dong, Yiwen and Sun, Chengnian},
  title = {Ad Hoc Syntax-Guided Program Reduction},
  year = {2023},
  publisher = {Association for Computing Machinery},
  doi = {10.1145/3611643.3613101},
  booktitle = {Proceedings of the 31st ACM Joint European Software Engineering Conference and Symposium on the Foundations of Software Engineering},
  pages = {2137–2141},
}

5. On the Caching Schemes to Speed Up Program Reduction (TOSEM, pdf)

@article{perses-caching,
  title={On the Caching Schemes to Speed Up Program Reduction},
  author={Tian, Yongqiang and Zhang, Xueyan and Dong, Yiwen and Xu, Zhenyang and Zhang, Mengxiao and Jiang, Yu and Cheung, Shing-Chi and Sun, Chengnian},
  journal={ACM Transactions on Software Engineering and Methodology},
  volume={33},
  number={1},
  pages={1--30},
  year={2023},
  publisher={ACM New York, NY, USA}
}

6. LPR: Large language models-aided program reduction (ISSTA 2024, pdf)

@inproceedings{perses-lpr,
  title={LPR: Large Language Models-Aided Program Reduction},
  author={Zhang, Mengxiao and Tian, Yongqiang and Xu, Zhenyang and Dong, Yiwen and Tan, Shin Hwei and Sun, Chengnian},
  booktitle={Proceedings of the 33rd ACM SIGSOFT International Symposium on Software Testing and Analysis},
  pages={261--273},
  year={2024}
}

7. T-Rec: Fine-Grained Language-Agnostic Program Reduction Guided by Lexical Syntax (TOSEM, pdf)

@article{perses-trec,
  title={T-Rec: Fine-Grained Language-Agnostic Program Reduction Guided by Lexical Syntax},
  author={Xu, Zhenyang and Tian, Yongqiang and Zhang, Mengxiao and Zhang, Jiarui and Liu, Puzhuo and Jiang, Yu and Sun, Chengnian},
  journal={ACM Transactions on Software Engineering and Methodology},
  year={2024},
  publisher={ACM New York, NY}
}

8. WDD: Weighted Delta Debugging (ICSE, pdf)

@article{perses-wdd,
  title={WDD: Weighted Delta Debugging},
  author={Zhou, Xintong and Xu, Zhenyang and Zhang, Mengxiao and Tian, Yongqiang and Sun, Chengnian},
  booktitle={Proceedings of the 47th International Conference on Software Engineering},
  year={2025},
  doi = {10.1109/ICSE55347.2025.00071},
  publisher = {IEEE Computer Society},
}

9. Toward a Better Understanding of Probabilistic Delta Debugging (ICSE, pdf)

@article{perses-cdd,
  title={Toward a Better Understanding of Probabilistic Delta Debugging},
  author={Zhang, Mengxiao and Xu, Zhenyang and Tian, Yongqiang and Cheng, Xinru and Sun, Chengnian},
  booktitle={Proceedings of the 47th International Conference on Software Engineering},
  year={2025},
  doi = {10.1109/ICSE55347.2025.00117},
  publisher = {IEEE Computer Society},
}

10. Boosting Program Reduction with the Missing Piece of Syntax-Guided Transformations (OOPSLA, pdf)

@article{perses-sfc,
  title={Boosting Program Reduction with the Missing Piece of Syntax-Guided Transformation},
  author={Xu, Zhenyang and Tian, Yongqiang and Zhang, Mengxiao and Sun, Chengnian},
  journal={Proceedings of the ACM on Programming Languages},
  year={2025},
  doi = {10.1145/3763053},
  publisher = {Association for Computing Machinery},
}

11. Latra: A Template-Based Language-Agnostic Transformation Framework for Effective Program Reduction (ASE, pdf)

@article{perses-latra,
  title={Latra: A Template-Based Language-Agnostic Transformation Framework for Effective Program Reduction},
  author={Xu, Zhenyang and Wang, Yiran and Tian, Yongqiang and Zhang, Mengxiao and Sun, Chengnian},
  booktitle={Proceedings of the 40th IEEE/ACM International Conference on Automated Software Engineerin},
  year={2025},
  doi = {},
  publisher = {},
}

Acknowledgement

This project has been/was partially supported by NSERC Discovery, a project under WHJIL Lab, and CFI-JELF Project #40736.

The codebase was optimized with an open source license from JProfiler.