Skip to content

Commit

Permalink
Analyzing circuits.
Browse files Browse the repository at this point in the history
  • Loading branch information
markkurossi committed Jan 1, 2022
1 parent 4d97ba3 commit 786a159
Show file tree
Hide file tree
Showing 9 changed files with 370 additions and 9 deletions.
15 changes: 12 additions & 3 deletions apps/garbled/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// main.go
//
// Copyright (c) 2019-2021 Markku Rossi
// Copyright (c) 2019-2022 Markku Rossi
//
// All rights reserved.
//
Expand Down Expand Up @@ -69,6 +69,7 @@ func main() {
bmr := flag.Int("bmr", -1, "semi-honest secure BMR protocol player number")
doc := flag.String("doc", "",
"generate documentation about argument files")
analyze := flag.Bool("analyze", false, "analyze circuits")
flag.Parse()

log.SetFlags(0)
Expand Down Expand Up @@ -102,6 +103,7 @@ func main() {
if *ssa && !*compile {
params.NoCircCompile = true
}
params.CircAnalyze = *analyze

if len(*doc) > 0 {
doc, err := NewHTMLDoc(*doc)
Expand Down Expand Up @@ -194,8 +196,15 @@ func main() {
}
}

if verbose && circ != nil {
fmt.Printf("Circuit: %v\n", circ)
if circ != nil {
circ.AssignLevels()

if params.CircAnalyze {
circ.Analyze()
}
if verbose {
fmt.Printf("Circuit: %v\n", circ)
}
}

if *ssa || *compile || *stream {
Expand Down
42 changes: 42 additions & 0 deletions circuit/analyze.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Copyright (c) 2021 Markku Rossi
//
// All rights reserved.
//

package circuit

import (
"fmt"
)

// Analyze identifies potential optimizations for the circuit.
func (c *Circuit) Analyze() {
fmt.Printf("analyzing circuit %v\n", c)

from := make([][]Gate, c.NumWires)
to := make([][]Gate, c.NumWires)

// Collect wire inputs and outputs.
for _, g := range c.Gates {
switch g.Op {
case XOR, XNOR, AND, OR:
to[g.Input1] = append(to[g.Input1], g)
fallthrough

case INV:
to[g.Input0] = append(to[g.Input0], g)
from[g.Output] = append(to[g.Output], g)
}
}

// INV gates as single output of input gate.
for _, g := range c.Gates {
if g.Op != INV {
continue
}
if len(to[g.Input0]) == 1 && len(from[g.Input0]) == 1 {
fmt.Printf("%v -> %v\n", from[g.Input0][0].Op, g.Op)
}
}
}
61 changes: 59 additions & 2 deletions circuit/circuit.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (c) 2019-2021 Markku Rossi
// Copyright (c) 2019-2022 Markku Rossi
//
// All rights reserved.
//
Expand Down Expand Up @@ -28,17 +28,25 @@ const (
OR
INV
Count
NumLevels
MaxWidth
)

// Stats holds statistics about circuit operations.
type Stats [Count + 1]uint64
type Stats [MaxWidth + 1]uint64

// Add adds the argument statistics to this statistics object.
func (stats *Stats) Add(o Stats) {
for i := XOR; i < Count; i++ {
stats[i] += o[i]
}
stats[Count]++

for i := NumLevels; i <= MaxWidth; i++ {
if o[i] > stats[i] {
stats[i] = o[i]
}
}
}

// Count returns the number of gates in the statistics object.
Expand Down Expand Up @@ -67,6 +75,8 @@ func (stats Stats) String() string {
}
result += fmt.Sprintf(" xor=%d", stats[XOR]+stats[XNOR])
result += fmt.Sprintf(" !xor=%d", stats[AND]+stats[OR]+stats[INV])
result += fmt.Sprintf(" levels=%d", stats[NumLevels])
result += fmt.Sprintf(" width=%d", stats[MaxWidth])
return result
}

Expand Down Expand Up @@ -336,12 +346,59 @@ func (c *Circuit) Dump() {
}
}

// AssignLevels assigns levels for gates. The level desribes how many
// steps away the gate is from input wires.
func (c *Circuit) AssignLevels() {
levels := make([]Level, c.NumWires)
countByLevel := make([]uint32, c.NumWires)

var max Level

for _, gate := range c.Gates {
level := levels[gate.Input0]
if gate.Op != INV {
l1 := levels[gate.Input1]
if l1 > level {
level = l1
}
}
gate.Level = level
countByLevel[level]++

level++

levels[gate.Output] = level
if level > max {
max = level
}
}
c.Stats[NumLevels] = uint64(max)

var maxWidth uint32
for _, count := range countByLevel {
if count > maxWidth {
maxWidth = count
}
}
if false {
for i := 0; i < int(max); i++ {
fmt.Printf("%v,%v\n", i, countByLevel[i])
}
}

c.Stats[MaxWidth] = uint64(maxWidth)
}

// Level defines gate's distance from input wires.
type Level uint32

// Gate specifies a boolean gate.
type Gate struct {
Input0 Wire
Input1 Wire
Output Wire
Op Operation
Level Level
}

func (g Gate) String() string {
Expand Down
18 changes: 18 additions & 0 deletions circuit/circuit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Copyright (c) 2022 Markku Rossi
//
// All rights reserved.
//

package circuit

import (
"fmt"
"testing"
"unsafe"
)

func TestSize(t *testing.T) {
var g Gate
fmt.Printf("sizeof(Gate)=%d\n", unsafe.Sizeof(g))
}
4 changes: 3 additions & 1 deletion compiler/ast/builtin.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (c) 2019-2021 Markku Rossi
// Copyright (c) 2019-2022 Markku Rossi
//
// All rights reserved.
//
Expand Down Expand Up @@ -368,6 +368,8 @@ func nativeCircuit(name string, block *ssa.Block, ctx *Codegen,
}
}

circ.AssignLevels()

if ctx.Verbose {
fmt.Printf(" - native %s: %v\n", name, circ)
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/ssa/circuitgen.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (c) 2020-2021 Markku Rossi
// Copyright (c) 2020-2022 Markku Rossi
//
// All rights reserved.
//
Expand Down
9 changes: 7 additions & 2 deletions compiler/ssa/streamer.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (c) 2020-2021 Markku Rossi
// Copyright (c) 2020-2022 Markku Rossi
//
// All rights reserved.
//
Expand Down Expand Up @@ -517,6 +517,7 @@ func (prog *Program) StreamCircuit(conn *p2p.Conn, params *utils.Params,
if params.Verbose && circuit.StreamDebug {
fmt.Printf("%05d: - %s\n", idx, circ)
}
circ.AssignLevels()
}
if false {
circ.Dump()
Expand Down Expand Up @@ -594,7 +595,7 @@ func (prog *Program) StreamCircuit(conn *p2p.Conn, params *utils.Params,
prog.numWires)

if params.Diagnostics {
tab := tabulate.New(tabulate.CompactUnicode)
tab := tabulate.New(tabulate.CompactUnicodeLight)
tab.Header("Instr").SetAlign(tabulate.ML)
tab.Header("Count").SetAlign(tabulate.MR)
tab.Header("XOR").SetAlign(tabulate.MR)
Expand All @@ -603,6 +604,8 @@ func (prog *Program) StreamCircuit(conn *p2p.Conn, params *utils.Params,
tab.Header("OR").SetAlign(tabulate.MR)
tab.Header("INV").SetAlign(tabulate.MR)
tab.Header("!XOR").SetAlign(tabulate.MR)
tab.Header("L").SetAlign(tabulate.MR)
tab.Header("W").SetAlign(tabulate.MR)

var keys []string
for k := range istats {
Expand All @@ -626,6 +629,8 @@ func (prog *Program) StreamCircuit(conn *p2p.Conn, params *utils.Params,
row.Column(fmt.Sprintf("%d", stats[circuit.INV]))
row.Column(fmt.Sprintf("%d",
stats[circuit.OR]+stats[circuit.AND]+stats[circuit.INV]))
row.Column(fmt.Sprintf("%d", stats[circuit.NumLevels]))
row.Column(fmt.Sprintf("%d", stats[circuit.MaxWidth]))
}
}
tab.Print(os.Stdout)
Expand Down
1 change: 1 addition & 0 deletions compiler/utils/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Params struct {
CircOut io.WriteCloser
CircDotOut io.WriteCloser
CircFormat string
CircAnalyze bool

CircMultArrayTreshold int

Expand Down
Loading

0 comments on commit 786a159

Please sign in to comment.