expanded readme

This commit is contained in:
Daniel Krueger 2021-03-07 22:59:23 +01:00
parent da985e084c
commit 35de32463a
4 changed files with 85 additions and 9 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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