on master help sign in
Add fold benchmark
commit8de5ea9fa34db833c94e1c6a37750712a56d9cc6 authorJasper Van der Jeugt <jaspervdj@gmail.com> dateThu 16 Jun 2011, 15:12 (15 years ago) parent4e79b4e
3 files changed+120
tests/benchmarks/ruby/fold.rb+50 tests/benchmarks/src/Data/Text/Benchmarks.hs+2 tests/benchmarks/src/Data/Text/Benchmarks/Programs/Fold.hs+68
tests/benchmarks/ruby/fold.rbnew file+50
@@ -0,0 +1,50 @@
1+#!/usr/bin/env ruby
2+
3+require './utils.rb'
4+
5+def fold(filename, max_width)
6+ File.open(filename, 'r:utf-8') do |file|
7+ # Words in this paragraph
8+ paragraph = []
9+
10+ file.each_line do |line|
11+ # If we encounter an empty line, we reformat and dump the current
12+ # paragraph
13+ if line.strip.empty? then
14+ puts fold_paragraph(paragraph, max_width)
15+ puts
16+ paragraph = []
17+ # Otherwise, we append the words found in the line to the paragraph
18+ else
19+ paragraph.concat line.split
20+ end
21+ end
22+
23+ # Last paragraph
24+ puts fold_paragraph(paragraph, max_width) unless paragraph.empty?
25+ end
26+end
27+
28+# Fold a single paragraph to the desired width
29+def fold_paragraph(paragraph, max_width)
30+ # Gradually build our output
31+ str = paragraph.first
32+ width = str.length
33+
34+ paragraph.drop(1).each do |word|
35+ if width + word.length + 1 <= max_width then
36+ str += ' ' + word
37+ width += word.length + 1
38+ else
39+ str += "\n" + word
40+ width = word.length
41+ end
42+ end
43+
44+ str
45+end
46+
47+ARGV.each do |f|
48+ t = benchmark { fold(f, 80) }
49+ STDERR.puts "#{f}: #{t}"
50+end
tests/benchmarks/src/Data/Text/Benchmarks.hs+2
@@ -23,6 +23,7 @@ import qualified Data.Text.Benchmarks.WordFrequencies as WordFrequencies
2323
2424import qualified Data.Text.Benchmarks.Programs.BigTable as Programs.BigTable
2525import qualified Data.Text.Benchmarks.Programs.Cut as Programs.Cut
26+import qualified Data.Text.Benchmarks.Programs.Fold as Programs.Fold
2627import qualified Data.Text.Benchmarks.Programs.Sort as Programs.Sort
2728import qualified Data.Text.Benchmarks.Programs.StripTags as Programs.StripTags
2829import qualified Data.Text.Benchmarks.Programs.Throughput as Programs.Throughput
@@ -54,6 +55,7 @@ benchmarks = do
5455 ps <- bgroup "Programs" `fmap` sequence
5556 [ Programs.BigTable.benchmark sink
5657 , Programs.Cut.benchmark (tf "russian.txt") sink 20 40
58+ , Programs.Fold.benchmark (tf "russian.txt") sink
5759 , Programs.Sort.benchmark (tf "russian.txt") sink
5860 , Programs.StripTags.benchmark (tf "yiwiki.xml") sink
5961 , Programs.Throughput.benchmark (tf "russian.txt") sink
tests/benchmarks/src/Data/Text/Benchmarks/Programs/Fold.hsnew file+68
@@ -0,0 +1,68 @@
1+-- | Benchmark which formats paragraph, like the @sort@ unix utility.
2+--
3+-- Tested in this benchmark:
4+--
5+-- * Reading the file
6+--
7+-- * Splitting into paragraphs
8+--
9+-- * Reformatting the paragraphs to a certain line width
10+--
11+-- * Concatenating the results using the text builder
12+--
13+-- * Writing back to a handle
14+--
15+{-# LANGUAGE OverloadedStrings #-}
16+module Data.Text.Benchmarks.Programs.Fold
17+ ( benchmark
18+ ) where
19+
20+import Data.List (foldl')
21+import Data.List (intersperse)
22+import Data.Monoid (mempty, mappend, mconcat)
23+import System.IO (Handle)
24+import Criterion (Benchmark, bench)
25+import qualified Data.Text as T
26+import qualified Data.Text.IO as T
27+import qualified Data.Text.Lazy.Builder as TLB
28+import qualified Data.Text.Lazy as TL
29+import qualified Data.Text.Lazy.IO as TL
30+
31+benchmark :: FilePath -> Handle -> IO Benchmark
32+benchmark i o = return $
33+ bench "Fold" $ T.readFile i >>= TL.hPutStr o . fold 80
34+
35+-- | We represent a paragraph by a word list
36+--
37+type Paragraph = [T.Text]
38+
39+-- | Fold a text
40+--
41+fold :: Int -> T.Text -> TL.Text
42+fold maxWidth = TLB.toLazyText . mconcat .
43+ intersperse "\n\n" . map (foldParagraph maxWidth) . paragraphs
44+
45+-- | Fold a paragraph
46+--
47+foldParagraph :: Int -> Paragraph -> TLB.Builder
48+foldParagraph _ [] = mempty
49+foldParagraph max' (w : ws) = fst $ foldl' go (TLB.fromText w, T.length w) ws
50+ where
51+ go (builder, width) word
52+ | width + len + 1 <= max' =
53+ (builder `mappend` " " `mappend` word', width + len + 1)
54+ | otherwise =
55+ (builder `mappend` "\n" `mappend` word', len)
56+ where
57+ word' = TLB.fromText word
58+ len = T.length word
59+
60+-- | Divide a text into paragraphs
61+--
62+paragraphs :: T.Text -> [Paragraph]
63+paragraphs = splitParagraphs . map T.words . T.lines
64+ where
65+ splitParagraphs ls = case break null ls of
66+ ([], []) -> []
67+ (p, []) -> [concat p]
68+ (p, lr) -> concat p : splitParagraphs (dropWhile null lr)