mirror of
https://github.com/dnlkrgr/hsreduce.git
synced 2024-11-22 15:09:55 +03:00
expanded readme
This commit is contained in:
parent
da985e084c
commit
35de32463a
79
README.md
79
README.md
@ -1,4 +1,77 @@
|
|||||||
|
|
||||||
|
|
||||||
# hsreduce
|
# hsreduce
|
||||||
Reducing Haskell programs for easier debugging of GHC bugs
|
|
||||||
|
Reducing Haskell programs for easier debugging of GHC crashes or performance regressions.
|
||||||
|
|
||||||
|
## Build Status
|
||||||
|
|
||||||
|
[![GHC 8.10.1](https://github.com/dnlkrgr/hsreduce/actions/workflows/haskell.yml/badge.svg)](https://github.com/dnlkrgr/hsreduce/actions/workflows/haskell.yml)
|
||||||
|
|
||||||
|
## Installing
|
||||||
|
|
||||||
|
1. Clone the repo
|
||||||
|
1. (Optional) Run `nix-shell`
|
||||||
|
1. Run `cabal install` or `stack install`
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Reducing
|
||||||
|
|
||||||
|
The main use case of hsreduce is in reducing Haskell programs.
|
||||||
|
hsreduce expects as inputs a single Haskell file and a shell script which outputs whether the file is interesting.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hsreduce reduce --shellScript interesting.sh --testCase Bug.hs --numberOfThreads 4 --timeOut 30
|
||||||
|
```
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
|Parameter |Explanation |
|
||||||
|
|-----------------|-------------------------------------------------|
|
||||||
|
|--shellScript |path to the interestingness test |
|
||||||
|
|--testCase |path to the Haskell program you want to reduce |
|
||||||
|
|--numberOfThreads|self-explanatory |
|
||||||
|
|--timeout |after how many seconds should tests be terminated|
|
||||||
|
|
||||||
|
### How do I write interestingness tests?
|
||||||
|
|
||||||
|
Example: Let's say you have a large Haskell file that prints "hello world" when you run it, but you're only interested in which part of the program makes it do that.
|
||||||
|
I think a good interestingness test would look like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
ghc Bug.s && ./Bug |& grep 'hello world'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Merging
|
||||||
|
|
||||||
|
Another use case is merging cabal projects into single Haskell files, which can then be reduced.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hsreduce merge --projectType Executable --targetName containers
|
||||||
|
```
|
||||||
|
|
||||||
|
|Parameter |Explanation |
|
||||||
|
|-----------------|------------------------------------------|
|
||||||
|
|--projectType |enter either *Executable* or *Library* |
|
||||||
|
|--targetName |name of the cabal target you want to merge|
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
**Q: I find this to be strange behaviour: "a shell script that returns exit code 0 if the file contains interesting behavior (reproduces a bug) and returns 1 otherwise ". Surely it makes more sense that something that checks for buggy behaviour returns a non-zero exitcode if it finds a bug?**
|
||||||
|
|
||||||
|
A: You're correct.
|
||||||
|
But here reproducing the bug is the "normal behavior" that we seek and anything else not.
|
||||||
|
If a reduction is done that leads to a test case that crashes for another reason or leads to a timeout, then it's not "normal behavior".
|
||||||
|
|
||||||
|
**Q: what do you mean by reduction?**
|
||||||
|
|
||||||
|
A: By reduction I mean "making the Haskell file smaller to make it more easily readable by humans".
|
||||||
|
This is done by trying to delete various elements from the Haskell program or by simplifying elements.
|
||||||
|
|
||||||
|
## Other Questions
|
||||||
|
|
||||||
|
Don't hesitate to message me on twitter.com/dnlkrgr
|
||||||
|
@ -5,7 +5,7 @@ let
|
|||||||
name = "nixos-unstable-2020-12-25";
|
name = "nixos-unstable-2020-12-25";
|
||||||
url = "https://github.com/nixos/nixpkgs";
|
url = "https://github.com/nixos/nixpkgs";
|
||||||
ref = "refs/heads/nixos-unstable";
|
ref = "refs/heads/nixos-unstable";
|
||||||
rev = "257cbbcd3ab7bd96f5d24d50adc807de7c82e06d";
|
rev = "102eb68ceecbbd32ab1906a53ef5a7269dc9794a";
|
||||||
}) {};
|
}) {};
|
||||||
|
|
||||||
in
|
in
|
||||||
|
@ -36,12 +36,12 @@ import Util.Util
|
|||||||
|
|
||||||
|
|
||||||
hsmerge :: ProjectType -> T.Text -> IO ()
|
hsmerge :: ProjectType -> T.Text -> IO ()
|
||||||
hsmerge isExecutable targetName = do
|
hsmerge projectType targetName = do
|
||||||
let
|
let
|
||||||
filePath = "hie.yaml"
|
filePath = "hie.yaml"
|
||||||
targetTypeS = case isExecutable of
|
targetTypeS = case projectType of
|
||||||
Executable -> "exe"
|
Executable -> "exe"
|
||||||
Library -> "lib"
|
Library -> "lib"
|
||||||
fileContent = "cradle: {cabal: {component: \"" <> targetTypeS <> ":" <> targetName <> "\" }}"
|
fileContent = "cradle: {cabal: {component: \"" <> targetTypeS <> ":" <> targetName <> "\" }}"
|
||||||
|
|
||||||
TIO.writeFile filePath fileContent
|
TIO.writeFile filePath fileContent
|
||||||
|
@ -127,7 +127,8 @@ hsreduce' allActions (fromIntegral -> numberOfThreads) testAbs filePathAbs fileC
|
|||||||
|
|
||||||
when recordStatistics $ do
|
when recordStatistics $ do
|
||||||
|
|
||||||
perfStats <- mkPerformance (fromIntegral oldSize) (fromIntegral newSize) t1 t2 (fromIntegral numberOfThreads) successfulInvocations totalInvocations (getTokenDiff newState beginState) (getNameDiff newState beginState)
|
perfStats <-
|
||||||
|
mkPerformance (fromIntegral oldSize) (fromIntegral newSize) t1 t2 (fromIntegral numberOfThreads) successfulInvocations totalInvocations (getTokenDiff newState beginState) (getNameDiff newState beginState)
|
||||||
liftIO $ appendFile "hsreduce_performance.csv" $ show perfStats
|
liftIO $ appendFile "hsreduce_performance.csv" $ show perfStats
|
||||||
|
|
||||||
liftIO
|
liftIO
|
||||||
@ -175,6 +176,8 @@ deleteTempDirs numberOfThreads tChan = do
|
|||||||
t <- atomically $ readTChan tChan
|
t <- atomically $ readTChan tChan
|
||||||
removeDirRecur t
|
removeDirRecur t
|
||||||
|
|
||||||
|
arst
|
||||||
|
|
||||||
|
|
||||||
-- 1. check if the test-case is still interesting (it should be at the start of the loop!)
|
-- 1. check if the test-case is still interesting (it should be at the start of the loop!)
|
||||||
-- 2. set alive variable to false
|
-- 2. set alive variable to false
|
||||||
|
Loading…
Reference in New Issue
Block a user