github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/accounts/benchmark_manager_test.go (about)

     1  package accounts
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"runtime"
     8  	"strconv"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  )
    13  
    14  //func BenchmarkAccountSignScaling(b *testing.B) {
    15  //	var cases = []struct {
    16  //		dir                  string
    17  //		numKeyFiles          int
    18  //		resetAll, resetCache bool
    19  //	}{
    20  //		// You can use resetCache: false to save some time if you've already run the benchmark.
    21  //		// Note that if you make any changes to the structure of the cachedb you'll need to
    22  //		// dump and reinitialize accounts.db.
    23  //		{dir: "benchmark_keystore100", numKeyFiles: 100, resetAll: false, resetCache: true},
    24  //		//{dir: "benchmark_keystore100", numKeyFiles: 100, resetAll: false, resetCache: false},
    25  //		{dir: "benchmark_keystore500", numKeyFiles: 500, resetAll: false, resetCache: true},
    26  //		//{dir: "benchmark_keystore500", numKeyFiles: 500, resetAll: false, resetCache: false},
    27  //		{dir: "benchmark_keystore1k", numKeyFiles: 1000, resetAll: false, resetCache: true},
    28  //		//{dir: "benchmark_keystore1k", numKeyFiles: 1000, resetAll: false, resetCache: false},
    29  //		{dir: "benchmark_keystore5k", numKeyFiles: 5000, resetAll: false, resetCache: true},
    30  //		//{dir: "benchmark_keystore5k", numKeyFiles: 5000, resetAll: false, resetCache: false},
    31  //		{dir: "benchmark_keystore10k", numKeyFiles: 10000, resetAll: false, resetCache: true},
    32  //		//{dir: "benchmark_keystore10k", numKeyFiles: 10000, resetAll: false, resetCache: false},
    33  //		{dir: "benchmark_keystore20k", numKeyFiles: 20000, resetAll: false, resetCache: true},
    34  //		//{dir: "benchmark_keystore20k", numKeyFiles: 20000, resetAll: false, resetCache: false},
    35  //		{dir: "benchmark_keystore100k", numKeyFiles: 100000, resetAll: false, resetCache: true},
    36  //		//{dir: "benchmark_keystore100k", numKeyFiles: 100000, resetAll: false, resetCache: false},
    37  //		{dir: "benchmark_keystore500k", numKeyFiles: 500000, resetAll: false, resetCache: true},
    38  //		//{dir: "benchmark_keystore500k", numKeyFiles: 500000, resetAll: false, resetCache: false},
    39  //	}
    40  //
    41  //	for _, c := range cases {
    42  //		b.Run(fmt.Sprintf("KeyFiles#:%v, CacheFromScratch:%v", c.numKeyFiles, c.resetCache), func(b *testing.B) {
    43  //			am := setupBenchmarkAccountFlowFast(filepath.Join("testdata", c.dir), c.numKeyFiles, c.resetAll, c.resetCache, b)
    44  //			benchmarkAccountSignFast(am.keyStore.baseDir, am, c.numKeyFiles-1, b)
    45  //			am = nil
    46  //		})
    47  //	}
    48  //}
    49  //
    50  //func BenchmarkAccountFlowScaling(b *testing.B) {
    51  //	var cases = []struct {
    52  //		dir                  string
    53  //		numKeyFiles          int
    54  //		resetAll, resetCache bool
    55  //	}{
    56  //		{dir: "benchmark_keystore100", numKeyFiles: 100, resetAll: false, resetCache: true},
    57  //		//{dir: "benchmark_keystore100", numKeyFiles: 100, resetAll: false, resetCache: false},
    58  //		{dir: "benchmark_keystore500", numKeyFiles: 500, resetAll: false, resetCache: true},
    59  //		//{dir: "benchmark_keystore500", numKeyFiles: 500, resetAll: false, resetCache: false},
    60  //		{dir: "benchmark_keystore1k", numKeyFiles: 1000, resetAll: false, resetCache: true},
    61  //		//{dir: "benchmark_keystore1k", numKeyFiles: 1000, resetAll: false, resetCache: false},
    62  //		{dir: "benchmark_keystore5k", numKeyFiles: 5000, resetAll: false, resetCache: true},
    63  //		//{dir: "benchmark_keystore5k", numKeyFiles: 5000, resetAll: false, resetCache: false},
    64  //		{dir: "benchmark_keystore10k", numKeyFiles: 10000, resetAll: false, resetCache: true},
    65  //		//{dir: "benchmark_keystore10k", numKeyFiles: 10000, resetAll: false, resetCache: false},
    66  //		{dir: "benchmark_keystore20k", numKeyFiles: 20000, resetAll: false, resetCache: true},
    67  //		//{dir: "benchmark_keystore20k", numKeyFiles: 20000, resetAll: false, resetCache: false},
    68  //		{dir: "benchmark_keystore100k", numKeyFiles: 100000, resetAll: false, resetCache: true},
    69  //		//{dir: "benchmark_keystore100k", numKeyFiles: 100000, resetAll: false, resetCache: false},
    70  //		{dir: "benchmark_keystore500k", numKeyFiles: 500000, resetAll: false, resetCache: true},
    71  //		//{dir: "benchmark_keystore500k", numKeyFiles: 500000, resetAll: false, resetCache: false},
    72  //	}
    73  //
    74  //	for _, c := range cases {
    75  //		b.Run(fmt.Sprintf("KeyFiles#:%v, CacheFromScratch:%v", c.numKeyFiles, c.resetCache), func(b *testing.B) {
    76  //			am := setupBenchmarkAccountFlowFast(filepath.Join("testdata", c.dir), c.numKeyFiles, c.resetAll, c.resetCache, b)
    77  //			benchmarkAccountFlowFast(filepath.Join("testdata", c.dir), am, b)
    78  //			am = nil
    79  //		})
    80  //	}
    81  //}
    82  //
    83  //// Signing an account requires finding the keyfile.
    84  //func testAccountSign(am *Manager, account Account, dir string) error {
    85  //	if _, err := am.SignWithPassphrase(account.Address, "foo", testSigData); err != nil {
    86  //		return err
    87  //	}
    88  //	return nil
    89  //}
    90  //
    91  func testAccountFlow(am *Manager, dir string) error {
    92  
    93  	// Create.
    94  	a, err := am.NewAccount("foo")
    95  	if err != nil {
    96  		return err
    97  	}
    98  	p, e := filepath.Abs(dir)
    99  	if e != nil {
   100  		return fmt.Errorf("could not determine absolute path for temp dir: %v", e)
   101  	}
   102  	if !strings.HasPrefix(a.File, p+"/") {
   103  		return fmt.Errorf("account file %s doesn't have dir prefix; %v", a.File, p)
   104  	}
   105  	stat, err := os.Stat(a.File)
   106  	if err != nil {
   107  		return fmt.Errorf("account file %s doesn't exist (%v)", a.File, err)
   108  	}
   109  	if runtime.GOOS != "windows" && stat.Mode() != 0600 {
   110  		return fmt.Errorf("account file has wrong mode: got %o, want %o", stat.Mode(), 0600)
   111  	}
   112  	if !am.HasAddress(a.Address) {
   113  		return fmt.Errorf("HasAddres(%x) should've returned true", a.Address)
   114  	}
   115  
   116  	// Update.
   117  	if err := am.Update(a, "foo", "bar"); err != nil {
   118  		return fmt.Errorf("Update error: %v", err)
   119  	}
   120  
   121  	// Sign with passphrase.
   122  	_, err = am.SignWithPassphrase(a.Address, "bar", testSigData) // testSigData is an empty [32]byte established in manager_test.go
   123  	if err != nil {
   124  		return fmt.Errorf("should be able to sign from account: %v", err)
   125  	}
   126  
   127  	// Delete.
   128  	if err := am.DeleteAccount(a, "bar"); err != nil {
   129  		return fmt.Errorf("DeleteAccount error: %v", err)
   130  	}
   131  	if _, err := os.Stat(a.File); err == nil || !os.IsNotExist(err) {
   132  		return fmt.Errorf("account file %s should be gone after DeleteAccount", a.File)
   133  	}
   134  	if am.HasAddress(a.Address) {
   135  		return fmt.Errorf("HasAddress(%x) should've returned true after DeleteAccount", a.Address)
   136  	}
   137  	return nil
   138  }
   139  
   140  //
   141  //func createTestAccount(am *Manager, dir string) error {
   142  //	a, err := am.NewAccount("foo")
   143  //	if err != nil {
   144  //		return err
   145  //	}
   146  //	p, e := filepath.Abs(dir)
   147  //	if e != nil {
   148  //		return fmt.Errorf("could not determine absolute path for temp dir: %v", e)
   149  //	}
   150  //	if !strings.HasPrefix(a.File, p+"/") {
   151  //		return fmt.Errorf("account file %s doesn't have dir prefix; %v", a.File, p)
   152  //	}
   153  //	stat, err := os.Stat(a.File)
   154  //	if err != nil {
   155  //		return fmt.Errorf("account file %s doesn't exist (%v)", a.File, err)
   156  //	}
   157  //	if runtime.GOOS != "windows" && stat.Mode() != 0600 {
   158  //		return fmt.Errorf("account file has wrong mode: got %o, want %o", stat.Mode(), 0600)
   159  //	}
   160  //	if !am.HasAddress(a.Address) {
   161  //		return fmt.Errorf("HasAddres(%x) should've returned true", a.Address)
   162  //	}
   163  //	return nil
   164  //}
   165  //
   166  //func getRandomIntN(n int) int {
   167  //	rand.Seed(time.Now().UTC().UnixNano())
   168  //	return int(rand.Int31n(int32(n)))
   169  //}
   170  //
   171  //// Test benchmark for CRUSD/account; create, update, sign, delete.
   172  //// Runs against setting of 10, 100, 1000, 10k, (100k, 1m) _existing_ accounts.
   173  //func benchmarkAccountSignFast(dir string, am *Manager, accountsN int, b *testing.B) {
   174  //	for i := 0; i < b.N; i++ {
   175  //		j := getRandomIntN(accountsN)
   176  //		b.Logf("signing with account index: %v", j)
   177  //		account, e := am.AccountByIndex(j)
   178  //		j = 0
   179  //		if e != nil {
   180  //			b.Fatal(e)
   181  //		}
   182  //		if e := testAccountSign(am, account, dir); e != nil {
   183  //			b.Fatalf("error signing with account: %v", e)
   184  //		}
   185  //	}
   186  //}
   187  //
   188  //func getFSvsCacheAccountN(dir string, ac *addrCache, b *testing.B) (fN, acN int) {
   189  //
   190  //	files, err := ioutil.ReadDir(ac.keydir)
   191  //	if err != nil {
   192  //		b.Fatalf("readdir: %v", err)
   193  //	}
   194  //
   195  //	acN = len(ac.accounts())
   196  //	fN = len(files) - 1 // - 1 because accounts.db is there too
   197  //
   198  //	return fN, acN
   199  //}
   200  //
   201  //func setupBenchmarkAccountFlowFast(dir string, n int, resetAll, resetCache bool, b *testing.B) {
   202  //	// Optionally: don't remove so we can compound accounts more quickly.
   203  //	if resetAll {
   204  //		b.Log("removing testdata keystore")
   205  //		os.RemoveAll(dir)
   206  //	} else if resetCache {
   207  //		b.Log("removing existing cache")
   208  //		os.Remove(filepath.Join(dir, "accounts.db")) // Remove cache db so we have to set up (scan()) every time.
   209  //	} else {
   210  //		b.Log("using existing cache and keystore")
   211  //	}
   212  //
   213  //	// Ensure any removed dir exists.
   214  //	if e := os.MkdirAll(dir, os.ModePerm); e != nil {
   215  //		b.Fatalf("could not mkdir -p '%v': %v", dir, e)
   216  //	}
   217  //
   218  //	files, err := ioutil.ReadDir(dir)
   219  //	if err != nil {
   220  //		b.Fatalf("readdir: %v", err)
   221  //	}
   222  //
   223  //	ks, e := newKeyStore(dir, veryLightScryptN, veryLightScryptP)
   224  //	if e != nil {
   225  //		b.Fatalf("keystore: %v", e)
   226  //	}
   227  //
   228  //	for i := len(files); i < n+1; i++ {
   229  //		_, _, err := storeNewKey(ks, "foo")
   230  //		if err != nil {
   231  //			b.Fatalf("storenewkey: %v", err)
   232  //		}
   233  //	}
   234  //	ks = nil
   235  //	files = nil
   236  //	//
   237  //	//manStart := time.Now()
   238  //	//am, err := NewManager(dir, veryLightScryptN, veryLightScryptP)
   239  //	//if err != nil {
   240  //	//	b.Fatal(err)
   241  //	//}
   242  //	//
   243  //	//am.get.watcher.running = true // cache.watcher.running = true // prevent unexpected reloads
   244  //	//
   245  //	//b.Logf("setup time for manager: %v", time.Since(manStart))
   246  //	//
   247  //	//fsN, acN := getFSvsCacheAccountN(dir, am.cache, b)
   248  //	//
   249  //	//if acN > fsN { // Can allow greater number of keyfiles, in the case that there are invalids or dupes.
   250  //	//	b.Errorf("accounts/files count mismatch: keyfiles: %v, accounts: %v", fsN, acN)
   251  //	//} else {
   252  //	//	b.Logf("files: %v, accounts: %v", fsN, acN)
   253  //	//}
   254  //	//
   255  //	//b.Logf("setup time for manager: %v", time.Since(manStart))
   256  //	//
   257  //	//b.ResetTimer() // _benchmark_ timer, not setup timer.
   258  //	//
   259  //	//return am
   260  //}
   261  //
   262  //// Test benchmark for CRUSD/account; create, update, sign, delete.
   263  //// Runs against setting of 10, 100, 1000, 10k, (100k, 1m) _existing_ accounts.
   264  //func benchmarkAccountFlowFast(dir string, am *Manager, b *testing.B) {
   265  //	for i := 0; i < b.N; i++ {
   266  //		if e := testAccountFlow(am, dir); e != nil {
   267  //			b.Fatalf("error setting up account: %v", e)
   268  //		}
   269  //	}
   270  //}
   271  
   272  func BenchmarkManager_SignWithPassphrase(b *testing.B) {
   273  	var cases = []struct {
   274  		numKeyFiles               int
   275  		wantCacheDB, resetCacheDB bool
   276  	}{
   277  		// You can use resetCache: false to save some time if you've already run the benchmark.
   278  		// Note that if you make any changes to the structure of the cachedb you'll need to
   279  		// dump and reinitialize accounts.db.
   280  		{numKeyFiles: 100, wantCacheDB: false, resetCacheDB: false},
   281  		{numKeyFiles: 100, wantCacheDB: true, resetCacheDB: false},
   282  		{numKeyFiles: 500, wantCacheDB: false, resetCacheDB: false},
   283  		{numKeyFiles: 500, wantCacheDB: true, resetCacheDB: false},
   284  		{numKeyFiles: 1000, wantCacheDB: false, resetCacheDB: false},
   285  		{numKeyFiles: 1000, wantCacheDB: true, resetCacheDB: false},
   286  		{numKeyFiles: 5000, wantCacheDB: false, resetCacheDB: false},
   287  		{numKeyFiles: 5000, wantCacheDB: true, resetCacheDB: false},
   288  		{numKeyFiles: 10000, wantCacheDB: false, resetCacheDB: false},
   289  		{numKeyFiles: 10000, wantCacheDB: true, resetCacheDB: false},
   290  		{numKeyFiles: 20000, wantCacheDB: false, resetCacheDB: false},
   291  		{numKeyFiles: 20000, wantCacheDB: true, resetCacheDB: false},
   292  		{numKeyFiles: 100000, wantCacheDB: false, resetCacheDB: false},
   293  		{numKeyFiles: 100000, wantCacheDB: true, resetCacheDB: false},
   294  		//{numKeyFiles: 200000, wantCacheDB: false, resetCacheDB: false},
   295  		{numKeyFiles: 200000, wantCacheDB: true, resetCacheDB: false},
   296  		//{numKeyFiles: 500000, wantCacheDB: false, resetCacheDB: false},
   297  		{numKeyFiles: 500000, wantCacheDB: true, resetCacheDB: false},
   298  	}
   299  
   300  	for _, c := range cases {
   301  		b.Run(fmt.Sprintf("CRUSD:KeyFiles#:%v,DB:%v,reset:%v", c.numKeyFiles, c.wantCacheDB, c.resetCacheDB), func(b *testing.B) {
   302  			benchmarkManager_SignWithPassphrase(c.numKeyFiles, c.wantCacheDB, c.resetCacheDB, b)
   303  		})
   304  	}
   305  }
   306  
   307  func benchmarkManager_SignWithPassphrase(n int, wantcachedb bool, resetcachedb bool, b *testing.B) {
   308  
   309  	// 20000 -> 20k
   310  	staticKeyFilesResourcePath := strconv.Itoa(n)
   311  	if strings.HasSuffix(staticKeyFilesResourcePath, "000") {
   312  		staticKeyFilesResourcePath = strings.TrimSuffix(staticKeyFilesResourcePath, "000")
   313  		staticKeyFilesResourcePath += "k"
   314  	}
   315  
   316  	staticKeyFilesResourcePath = filepath.Join("testdata", "benchmark_keystore"+staticKeyFilesResourcePath)
   317  
   318  	if !wantcachedb {
   319  		p, e := filepath.Abs(staticKeyFilesResourcePath)
   320  		if e != nil {
   321  			b.Fatal(e)
   322  		}
   323  		staticKeyFilesResourcePath = p
   324  	}
   325  
   326  	start := time.Now()
   327  	am, me := NewManager(staticKeyFilesResourcePath, veryLightScryptN, veryLightScryptP, wantcachedb)
   328  	if me != nil {
   329  		b.Fatal(me)
   330  	}
   331  	elapsed := time.Since(start)
   332  	b.Logf("establishing manager for %v accs: %v", n, elapsed)
   333  
   334  	accs := am.Accounts()
   335  	if !wantcachedb {
   336  		am.ac.getWatcher().running = true
   337  	}
   338  	if len(accs) == 0 {
   339  		b.Fatal("no accounts")
   340  	}
   341  
   342  	// Set up 1 DNE and 3 existing accs.
   343  	// Using the last accs because they should take the longest to iterate to.
   344  	var signAccounts []Account
   345  	signAccounts = accs[(len(accs) - 4):]
   346  	accs = nil
   347  
   348  	b.ResetTimer() // _benchmark_ timer, not setup timer.
   349  
   350  	for i := 0; i < b.N; i++ {
   351  		for _, a := range signAccounts {
   352  			if _, e := am.SignWithPassphrase(a.Address, "foo", testSigData); e != nil {
   353  				b.Errorf("signing with passphrase: %v", e)
   354  			}
   355  		}
   356  	}
   357  	am.ac.close()
   358  	am = nil
   359  }
   360  
   361  func BenchmarkManagerCRUSD(b *testing.B) {
   362  	var cases = []struct {
   363  		numKeyFiles               int
   364  		wantCacheDB, resetCacheDB bool
   365  	}{
   366  		// You can use resetCache: false to save some time if you've already run the benchmark.
   367  		// Note that if you make any changes to the structure of the cachedb you'll need to
   368  		// dump and reinitialize accounts.db.
   369  		{numKeyFiles: 100, wantCacheDB: false, resetCacheDB: false},
   370  		{numKeyFiles: 100, wantCacheDB: true, resetCacheDB: false},
   371  		{numKeyFiles: 500, wantCacheDB: false, resetCacheDB: false},
   372  		{numKeyFiles: 500, wantCacheDB: true, resetCacheDB: false},
   373  		{numKeyFiles: 1000, wantCacheDB: false, resetCacheDB: false},
   374  		{numKeyFiles: 1000, wantCacheDB: true, resetCacheDB: false},
   375  		{numKeyFiles: 5000, wantCacheDB: false, resetCacheDB: false},
   376  		{numKeyFiles: 5000, wantCacheDB: true, resetCacheDB: false},
   377  		{numKeyFiles: 10000, wantCacheDB: false, resetCacheDB: false},
   378  		{numKeyFiles: 10000, wantCacheDB: true, resetCacheDB: false},
   379  		{numKeyFiles: 20000, wantCacheDB: false, resetCacheDB: false},
   380  		{numKeyFiles: 20000, wantCacheDB: true, resetCacheDB: false},
   381  		{numKeyFiles: 100000, wantCacheDB: false, resetCacheDB: false},
   382  		{numKeyFiles: 100000, wantCacheDB: true, resetCacheDB: false},
   383  		{numKeyFiles: 200000, wantCacheDB: false, resetCacheDB: false},
   384  		{numKeyFiles: 200000, wantCacheDB: true, resetCacheDB: false},
   385  		{numKeyFiles: 500000, wantCacheDB: false, resetCacheDB: false},
   386  		{numKeyFiles: 500000, wantCacheDB: true, resetCacheDB: false},
   387  	}
   388  
   389  	for _, c := range cases {
   390  		b.Run(fmt.Sprintf("CRUSD:KeyFiles#:%v,DB:%v,reset:%v", c.numKeyFiles, c.wantCacheDB, c.resetCacheDB), func(b *testing.B) {
   391  			benchmarkManager_CRUSD(c.numKeyFiles, c.wantCacheDB, c.resetCacheDB, b)
   392  		})
   393  	}
   394  }
   395  
   396  func benchmarkManager_CRUSD(n int, wantcachedb bool, resetcachedb bool, b *testing.B) {
   397  
   398  	// 20000 -> 20k
   399  	staticKeyFilesResourcePath := strconv.Itoa(n)
   400  	if strings.HasSuffix(staticKeyFilesResourcePath, "000") {
   401  		staticKeyFilesResourcePath = strings.TrimSuffix(staticKeyFilesResourcePath, "000")
   402  		staticKeyFilesResourcePath += "k"
   403  	}
   404  
   405  	staticKeyFilesResourcePath = filepath.Join("testdata", "benchmark_keystore"+staticKeyFilesResourcePath)
   406  
   407  	if !wantcachedb {
   408  		p, e := filepath.Abs(staticKeyFilesResourcePath)
   409  		if e != nil {
   410  			b.Fatal(e)
   411  		}
   412  		staticKeyFilesResourcePath = p
   413  	}
   414  
   415  	if resetcachedb {
   416  		os.Remove(filepath.Join(staticKeyFilesResourcePath, "accounts.db"))
   417  	}
   418  
   419  	start := time.Now()
   420  	am, me := NewManager(staticKeyFilesResourcePath, veryLightScryptN, veryLightScryptP, wantcachedb)
   421  	if !wantcachedb {
   422  		am.ac.getWatcher().running = true
   423  	}
   424  
   425  	if me != nil {
   426  		b.Fatal(me)
   427  	}
   428  	elapsed := time.Since(start)
   429  	b.Logf("establishing manager for %v accs: %v", n, elapsed)
   430  
   431  	b.ResetTimer() // _benchmark_ timer, not setup timer.
   432  
   433  	for i := 0; i < b.N; i++ {
   434  		if e := testAccountFlow(am, staticKeyFilesResourcePath); e != nil {
   435  			b.Errorf("account flow (CRUSD): %v (db: %v)", e, wantcachedb)
   436  		}
   437  	}
   438  	am.ac.close()
   439  	am = nil
   440  }