mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-04 03:27:23 -05:00 
			
		
		
		
	diagnostics: Implemented collection functions and create first metrics
- Also implemented robust error handling and failovers - Vendored klauspost/cpuid
This commit is contained in:
		
							parent
							
								
									8f0b44b8a4
								
							
						
					
					
						commit
						388ff6bc0a
					
				@ -27,6 +27,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/google/uuid"
 | 
						"github.com/google/uuid"
 | 
				
			||||||
 | 
						"github.com/klauspost/cpuid"
 | 
				
			||||||
	"github.com/mholt/caddy"
 | 
						"github.com/mholt/caddy"
 | 
				
			||||||
	"github.com/mholt/caddy/caddytls"
 | 
						"github.com/mholt/caddy/caddytls"
 | 
				
			||||||
	"github.com/mholt/caddy/diagnostics"
 | 
						"github.com/mholt/caddy/diagnostics"
 | 
				
			||||||
@ -51,6 +52,7 @@ func init() {
 | 
				
			|||||||
	flag.StringVar(&caddytls.DefaultEmail, "email", "", "Default ACME CA account email address")
 | 
						flag.StringVar(&caddytls.DefaultEmail, "email", "", "Default ACME CA account email address")
 | 
				
			||||||
	flag.DurationVar(&acme.HTTPClient.Timeout, "catimeout", acme.HTTPClient.Timeout, "Default ACME CA HTTP timeout")
 | 
						flag.DurationVar(&acme.HTTPClient.Timeout, "catimeout", acme.HTTPClient.Timeout, "Default ACME CA HTTP timeout")
 | 
				
			||||||
	flag.StringVar(&logfile, "log", "", "Process log file")
 | 
						flag.StringVar(&logfile, "log", "", "Process log file")
 | 
				
			||||||
 | 
						flag.BoolVar(&noDiag, "no-diagnostics", false, "Disable diagnostic reporting")
 | 
				
			||||||
	flag.StringVar(&caddy.PidFile, "pidfile", "", "Path to write pid file")
 | 
						flag.StringVar(&caddy.PidFile, "pidfile", "", "Path to write pid file")
 | 
				
			||||||
	flag.BoolVar(&caddy.Quiet, "quiet", false, "Quiet mode (no initialization output)")
 | 
						flag.BoolVar(&caddy.Quiet, "quiet", false, "Quiet mode (no initialization output)")
 | 
				
			||||||
	flag.StringVar(&revoke, "revoke", "", "Hostname for which to revoke the certificate")
 | 
						flag.StringVar(&revoke, "revoke", "", "Hostname for which to revoke the certificate")
 | 
				
			||||||
@ -88,7 +90,9 @@ func Run() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// initialize diagnostics client
 | 
						// initialize diagnostics client
 | 
				
			||||||
	initDiagnostics()
 | 
						if !noDiag {
 | 
				
			||||||
 | 
							initDiagnostics()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check for one-time actions
 | 
						// Check for one-time actions
 | 
				
			||||||
	if revoke != "" {
 | 
						if revoke != "" {
 | 
				
			||||||
@ -146,6 +150,23 @@ func Run() {
 | 
				
			|||||||
	// Execute instantiation events
 | 
						// Execute instantiation events
 | 
				
			||||||
	caddy.EmitEvent(caddy.InstanceStartupEvent, instance)
 | 
						caddy.EmitEvent(caddy.InstanceStartupEvent, instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Begin diagnostics (these are no-ops if diagnostics disabled)
 | 
				
			||||||
 | 
						diagnostics.Set("caddy_version", appVersion)
 | 
				
			||||||
 | 
						// TODO: plugins
 | 
				
			||||||
 | 
						diagnostics.Set("num_listeners", len(instance.Servers()))
 | 
				
			||||||
 | 
						diagnostics.Set("os", runtime.GOOS)
 | 
				
			||||||
 | 
						diagnostics.Set("arch", runtime.GOARCH)
 | 
				
			||||||
 | 
						diagnostics.Set("cpu", struct {
 | 
				
			||||||
 | 
							NumLogical int    `json:"num_logical"`
 | 
				
			||||||
 | 
							AESNI      bool   `json:"aes_ni"`
 | 
				
			||||||
 | 
							BrandName  string `json:"brand_name"`
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							NumLogical: runtime.NumCPU(),
 | 
				
			||||||
 | 
							AESNI:      cpuid.CPU.AesNi(),
 | 
				
			||||||
 | 
							BrandName:  cpuid.CPU.BrandName,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						diagnostics.StartEmitting()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Twiddle your thumbs
 | 
						// Twiddle your thumbs
 | 
				
			||||||
	instance.Wait()
 | 
						instance.Wait()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -321,6 +342,7 @@ var (
 | 
				
			|||||||
	version    bool
 | 
						version    bool
 | 
				
			||||||
	plugins    bool
 | 
						plugins    bool
 | 
				
			||||||
	validate   bool
 | 
						validate   bool
 | 
				
			||||||
 | 
						noDiag     bool
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Build information obtained with the help of -ldflags
 | 
					// Build information obtained with the help of -ldflags
 | 
				
			||||||
 | 
				
			|||||||
@ -29,6 +29,7 @@ import (
 | 
				
			|||||||
	"github.com/mholt/caddy/caddyfile"
 | 
						"github.com/mholt/caddy/caddyfile"
 | 
				
			||||||
	"github.com/mholt/caddy/caddyhttp/staticfiles"
 | 
						"github.com/mholt/caddy/caddyhttp/staticfiles"
 | 
				
			||||||
	"github.com/mholt/caddy/caddytls"
 | 
						"github.com/mholt/caddy/caddytls"
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/diagnostics"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const serverType = "http"
 | 
					const serverType = "http"
 | 
				
			||||||
@ -205,6 +206,8 @@ func (h *httpContext) MakeServers() ([]caddy.Server, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						diagnostics.Set("num_sites", len(h.siteConfigs))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// we must map (group) each config to a bind address
 | 
						// we must map (group) each config to a bind address
 | 
				
			||||||
	groups, err := groupSiteConfigsByListenAddr(h.siteConfigs)
 | 
						groups, err := groupSiteConfigsByListenAddr(h.siteConfigs)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,7 @@ import (
 | 
				
			|||||||
	"github.com/mholt/caddy"
 | 
						"github.com/mholt/caddy"
 | 
				
			||||||
	"github.com/mholt/caddy/caddyhttp/staticfiles"
 | 
						"github.com/mholt/caddy/caddyhttp/staticfiles"
 | 
				
			||||||
	"github.com/mholt/caddy/caddytls"
 | 
						"github.com/mholt/caddy/caddytls"
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/diagnostics"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Server is the HTTP server implementation.
 | 
					// Server is the HTTP server implementation.
 | 
				
			||||||
@ -345,6 +346,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go diagnostics.AppendUniqueString("user_agent", r.Header.Get("User-Agent"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// copy the original, unchanged URL into the context
 | 
						// copy the original, unchanged URL into the context
 | 
				
			||||||
	// so it can be referenced by middlewares
 | 
						// so it can be referenced by middlewares
 | 
				
			||||||
	urlCopy := *r.URL
 | 
						urlCopy := *r.URL
 | 
				
			||||||
 | 
				
			|||||||
@ -26,6 +26,7 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/mholt/caddy"
 | 
						"github.com/mholt/caddy"
 | 
				
			||||||
 | 
						"github.com/mholt/caddy/diagnostics"
 | 
				
			||||||
	"github.com/xenolf/lego/acme"
 | 
						"github.com/xenolf/lego/acme"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -276,6 +277,8 @@ Attempts:
 | 
				
			|||||||
		break
 | 
							break
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go diagnostics.Increment("acme_certificates_obtained")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -350,8 +353,9 @@ func (c *ACMEClient) Renew(name string) error {
 | 
				
			|||||||
		return errors.New("too many renewal attempts; last error: " + err.Error())
 | 
							return errors.New("too many renewal attempts; last error: " + err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Executes Cert renew events
 | 
					 | 
				
			||||||
	caddy.EmitEvent(caddy.CertRenewEvent, name)
 | 
						caddy.EmitEvent(caddy.CertRenewEvent, name)
 | 
				
			||||||
 | 
						go diagnostics.Increment("acme_certificates_obtained")
 | 
				
			||||||
 | 
						go diagnostics.Increment("acme_certificates_renewed")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return saveCertResource(storage, newCertMeta)
 | 
						return saveCertResource(storage, newCertMeta)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										250
									
								
								diagnostics/collection.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								diagnostics/collection.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,250 @@
 | 
				
			|||||||
 | 
					// Copyright 2015 Light Code Labs, LLC
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package diagnostics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/google/uuid"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Init initializes this package so that it may
 | 
				
			||||||
 | 
					// be used. Do not call this function more than
 | 
				
			||||||
 | 
					// once. Init panics if it is called more than
 | 
				
			||||||
 | 
					// once or if the UUID value is empty. Once this
 | 
				
			||||||
 | 
					// function is called, the rest of the package
 | 
				
			||||||
 | 
					// may safely be used. If this function is not
 | 
				
			||||||
 | 
					// called, the collector functions may still be
 | 
				
			||||||
 | 
					// invoked, but they will be no-ops.
 | 
				
			||||||
 | 
					func Init(instanceID uuid.UUID) {
 | 
				
			||||||
 | 
						if enabled {
 | 
				
			||||||
 | 
							panic("already initialized")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if instanceID.String() == "" {
 | 
				
			||||||
 | 
							panic("empty UUID")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						instanceUUID = instanceID
 | 
				
			||||||
 | 
						enabled = true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// StartEmitting sends the current payload and begins the
 | 
				
			||||||
 | 
					// transmission cycle for updates. This is the first
 | 
				
			||||||
 | 
					// update sent, and future ones will be sent until
 | 
				
			||||||
 | 
					// StopEmitting is called.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This function is non-blocking (it spawns a new goroutine).
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This function panics if it was called more than once.
 | 
				
			||||||
 | 
					// It is a no-op if this package was not initialized.
 | 
				
			||||||
 | 
					func StartEmitting() {
 | 
				
			||||||
 | 
						if !enabled {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						updateTimerMu.Lock()
 | 
				
			||||||
 | 
						if updateTimer != nil {
 | 
				
			||||||
 | 
							updateTimerMu.Unlock()
 | 
				
			||||||
 | 
							panic("updates already started")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						updateTimerMu.Unlock()
 | 
				
			||||||
 | 
						updateMu.Lock()
 | 
				
			||||||
 | 
						if updating {
 | 
				
			||||||
 | 
							updateMu.Unlock()
 | 
				
			||||||
 | 
							panic("update already in progress")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						updateMu.Unlock()
 | 
				
			||||||
 | 
						go logEmit(false)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// StopEmitting sends the current payload and terminates
 | 
				
			||||||
 | 
					// the update cycle. No more updates will be sent.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// It is a no-op if the package was never initialized
 | 
				
			||||||
 | 
					// or if emitting was never started.
 | 
				
			||||||
 | 
					func StopEmitting() {
 | 
				
			||||||
 | 
						if !enabled {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						updateTimerMu.Lock()
 | 
				
			||||||
 | 
						if updateTimer == nil {
 | 
				
			||||||
 | 
							updateTimerMu.Unlock()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						updateTimerMu.Unlock()
 | 
				
			||||||
 | 
						logEmit(true)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Set puts a value in the buffer to be included
 | 
				
			||||||
 | 
					// in the next emission. It overwrites any
 | 
				
			||||||
 | 
					// previous value.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This function is safe for multiple goroutines,
 | 
				
			||||||
 | 
					// and it is recommended to call this using the
 | 
				
			||||||
 | 
					// go keyword after the call to SendHello so it
 | 
				
			||||||
 | 
					// doesn't block crucial code.
 | 
				
			||||||
 | 
					func Set(key string, val interface{}) {
 | 
				
			||||||
 | 
						if !enabled {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufferMu.Lock()
 | 
				
			||||||
 | 
						if bufferItemCount >= maxBufferItems {
 | 
				
			||||||
 | 
							bufferMu.Unlock()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, ok := buffer[key]; !ok {
 | 
				
			||||||
 | 
							bufferItemCount++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buffer[key] = val
 | 
				
			||||||
 | 
						bufferMu.Unlock()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Append appends value to a list named key.
 | 
				
			||||||
 | 
					// If key is new, a new list will be created.
 | 
				
			||||||
 | 
					// If key maps to a type that is not a list,
 | 
				
			||||||
 | 
					// an error is logged, and this is a no-op.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// TODO: is this function needed/useful?
 | 
				
			||||||
 | 
					func Append(key string, value interface{}) {
 | 
				
			||||||
 | 
						if !enabled {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufferMu.Lock()
 | 
				
			||||||
 | 
						if bufferItemCount >= maxBufferItems {
 | 
				
			||||||
 | 
							bufferMu.Unlock()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// TODO: Test this...
 | 
				
			||||||
 | 
						bufVal, inBuffer := buffer[key]
 | 
				
			||||||
 | 
						sliceVal, sliceOk := bufVal.([]interface{})
 | 
				
			||||||
 | 
						if inBuffer && !sliceOk {
 | 
				
			||||||
 | 
							bufferMu.Unlock()
 | 
				
			||||||
 | 
							log.Printf("[PANIC] Diagnostics: key %s already used for non-slice value", key)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if sliceVal == nil {
 | 
				
			||||||
 | 
							buffer[key] = []interface{}{value}
 | 
				
			||||||
 | 
						} else if sliceOk {
 | 
				
			||||||
 | 
							buffer[key] = append(sliceVal, value)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufferItemCount++
 | 
				
			||||||
 | 
						bufferMu.Unlock()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AppendUniqueString adds value to a set named key.
 | 
				
			||||||
 | 
					// Set items are unordered. Values in the set
 | 
				
			||||||
 | 
					// are unique, but repeat values are counted.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If key is new, a new set will be created.
 | 
				
			||||||
 | 
					// If key maps to a type that is not a string
 | 
				
			||||||
 | 
					// set, an error is logged, and this is a no-op.
 | 
				
			||||||
 | 
					func AppendUniqueString(key, value string) {
 | 
				
			||||||
 | 
						if !enabled {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufferMu.Lock()
 | 
				
			||||||
 | 
						if bufferItemCount >= maxBufferItems {
 | 
				
			||||||
 | 
							bufferMu.Unlock()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufVal, inBuffer := buffer[key]
 | 
				
			||||||
 | 
						mapVal, mapOk := bufVal.(map[string]int)
 | 
				
			||||||
 | 
						if inBuffer && !mapOk {
 | 
				
			||||||
 | 
							bufferMu.Unlock()
 | 
				
			||||||
 | 
							log.Printf("[PANIC] Diagnostics: key %s already used for non-map value", key)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if mapVal == nil {
 | 
				
			||||||
 | 
							buffer[key] = map[string]int{value: 1}
 | 
				
			||||||
 | 
							bufferItemCount++
 | 
				
			||||||
 | 
						} else if mapOk {
 | 
				
			||||||
 | 
							mapVal[value]++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufferMu.Unlock()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AppendUniqueInt adds value to a set named key.
 | 
				
			||||||
 | 
					// Set items are unordered. Values in the set
 | 
				
			||||||
 | 
					// are unique, but repeat values are counted.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If key is new, a new set will be created.
 | 
				
			||||||
 | 
					// If key maps to a type that is not an integer
 | 
				
			||||||
 | 
					// set, an error is logged, and this is a no-op.
 | 
				
			||||||
 | 
					func AppendUniqueInt(key string, value int) {
 | 
				
			||||||
 | 
						if !enabled {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufferMu.Lock()
 | 
				
			||||||
 | 
						if bufferItemCount >= maxBufferItems {
 | 
				
			||||||
 | 
							bufferMu.Unlock()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufVal, inBuffer := buffer[key]
 | 
				
			||||||
 | 
						mapVal, mapOk := bufVal.(map[int]int)
 | 
				
			||||||
 | 
						if inBuffer && !mapOk {
 | 
				
			||||||
 | 
							bufferMu.Unlock()
 | 
				
			||||||
 | 
							log.Printf("[PANIC] Diagnostics: key %s already used for non-map value", key)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if mapVal == nil {
 | 
				
			||||||
 | 
							buffer[key] = map[int]int{value: 1}
 | 
				
			||||||
 | 
							bufferItemCount++
 | 
				
			||||||
 | 
						} else if mapOk {
 | 
				
			||||||
 | 
							mapVal[value]++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufferMu.Unlock()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Increment adds 1 to a value named key.
 | 
				
			||||||
 | 
					// If it does not exist, it is created with
 | 
				
			||||||
 | 
					// a value of 1. If key maps to a type that
 | 
				
			||||||
 | 
					// is not an integer, an error is logged,
 | 
				
			||||||
 | 
					// and this is a no-op.
 | 
				
			||||||
 | 
					func Increment(key string) {
 | 
				
			||||||
 | 
						incrementOrDecrement(key, true)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Decrement is the same as increment except
 | 
				
			||||||
 | 
					// it subtracts 1.
 | 
				
			||||||
 | 
					func Decrement(key string) {
 | 
				
			||||||
 | 
						incrementOrDecrement(key, false)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// inc == true:  increment
 | 
				
			||||||
 | 
					// inc == false: decrement
 | 
				
			||||||
 | 
					func incrementOrDecrement(key string, inc bool) {
 | 
				
			||||||
 | 
						if !enabled {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufferMu.Lock()
 | 
				
			||||||
 | 
						bufVal, inBuffer := buffer[key]
 | 
				
			||||||
 | 
						intVal, intOk := bufVal.(int)
 | 
				
			||||||
 | 
						if inBuffer && !intOk {
 | 
				
			||||||
 | 
							bufferMu.Unlock()
 | 
				
			||||||
 | 
							log.Printf("[PANIC] Diagnostics: key %s already used for non-integer value", key)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !inBuffer {
 | 
				
			||||||
 | 
							if bufferItemCount >= maxBufferItems {
 | 
				
			||||||
 | 
								bufferMu.Unlock()
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							bufferItemCount++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if inc {
 | 
				
			||||||
 | 
							buffer[key] = intVal + 1
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							buffer[key] = intVal - 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						bufferMu.Unlock()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -12,14 +12,252 @@
 | 
				
			|||||||
// See the License for the specific language governing permissions and
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
// limitations under the License.
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Package diagnostics implements the client for server-side diagnostics
 | 
				
			||||||
 | 
					// of the network. Functions in this package are synchronous and blocking
 | 
				
			||||||
 | 
					// unless otherwise specified. For convenience, most functions here do
 | 
				
			||||||
 | 
					// not return errors, but errors are logged to the standard logger.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// To use this package, first call Init(). You can then call any of the
 | 
				
			||||||
 | 
					// collection/aggregation functions. Call StartEmitting() when you are
 | 
				
			||||||
 | 
					// ready to begin sending diagnostic updates.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// When collecting metrics (functions like Set, Append*, or Increment),
 | 
				
			||||||
 | 
					// it may be desirable and even recommended to run invoke them in a new
 | 
				
			||||||
 | 
					// goroutine (use the go keyword) in case there is lock contention;
 | 
				
			||||||
 | 
					// they are thread-safe (unless noted), and you may not want them to
 | 
				
			||||||
 | 
					// block the main thread of execution. However, sometimes blocking
 | 
				
			||||||
 | 
					// may be necessary too; for example, adding startup metrics to the
 | 
				
			||||||
 | 
					// buffer before the call to StartEmitting().
 | 
				
			||||||
package diagnostics
 | 
					package diagnostics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/google/uuid"
 | 
						"github.com/google/uuid"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Init(uuid uuid.UUID) {
 | 
					// logEmit calls emit and then logs the error, if any.
 | 
				
			||||||
	instanceUUID = uuid
 | 
					func logEmit(final bool) {
 | 
				
			||||||
 | 
						err := emit(final)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("[ERROR] Sending diganostics: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// emit sends an update to the diagnostics server.
 | 
				
			||||||
 | 
					// If final is true, no future updates will be scheduled.
 | 
				
			||||||
 | 
					// Otherwise, the next update will be scheduled.
 | 
				
			||||||
 | 
					func emit(final bool) error {
 | 
				
			||||||
 | 
						if !enabled {
 | 
				
			||||||
 | 
							return fmt.Errorf("diagnostics not enabled")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ensure only one update happens at a time;
 | 
				
			||||||
 | 
						// skip update if previous one still in progress
 | 
				
			||||||
 | 
						updateMu.Lock()
 | 
				
			||||||
 | 
						if updating {
 | 
				
			||||||
 | 
							updateMu.Unlock()
 | 
				
			||||||
 | 
							log.Println("[NOTICE] Skipping this diagnostics update because previous one is still working")
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						updating = true
 | 
				
			||||||
 | 
						updateMu.Unlock()
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							updateMu.Lock()
 | 
				
			||||||
 | 
							updating = false
 | 
				
			||||||
 | 
							updateMu.Unlock()
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// terminate any pending update if this is the last one
 | 
				
			||||||
 | 
						if final {
 | 
				
			||||||
 | 
							updateTimerMu.Lock()
 | 
				
			||||||
 | 
							updateTimer.Stop()
 | 
				
			||||||
 | 
							updateTimer = nil
 | 
				
			||||||
 | 
							updateTimerMu.Unlock()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						payloadBytes, err := makePayloadAndResetBuffer()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// this will hold the server's reply
 | 
				
			||||||
 | 
						var reply Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// transmit the payload - use a loop to retry in case of failure
 | 
				
			||||||
 | 
						for i := 0; i < 4; i++ {
 | 
				
			||||||
 | 
							if i > 0 && err != nil {
 | 
				
			||||||
 | 
								// don't hammer the server; first failure might have been
 | 
				
			||||||
 | 
								// a fluke, but back off more after that
 | 
				
			||||||
 | 
								log.Printf("[WARNING] Sending diagnostics (attempt %d): %v - waiting and retrying", i, err)
 | 
				
			||||||
 | 
								time.Sleep(time.Duration(i*i*i) * time.Second)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// send it
 | 
				
			||||||
 | 
							var resp *http.Response
 | 
				
			||||||
 | 
							resp, err = httpClient.Post(endpoint+instanceUUID.String(), "application/json", bytes.NewReader(payloadBytes))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// ensure we can read the response
 | 
				
			||||||
 | 
							if ct := resp.Header.Get("Content-Type"); (resp.StatusCode < 300 || resp.StatusCode >= 400) &&
 | 
				
			||||||
 | 
								!strings.Contains(ct, "json") {
 | 
				
			||||||
 | 
								err = fmt.Errorf("diagnostics server replied with unknown content-type: %s", ct)
 | 
				
			||||||
 | 
								resp.Body.Close()
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// read the response body
 | 
				
			||||||
 | 
							err = json.NewDecoder(resp.Body).Decode(&reply)
 | 
				
			||||||
 | 
							resp.Body.Close() // close response body as soon as we're done with it
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// ensure we won't slam the diagnostics server
 | 
				
			||||||
 | 
							if reply.NextUpdate < 1*time.Second {
 | 
				
			||||||
 | 
								reply.NextUpdate = defaultUpdateInterval
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// make sure we didn't send the update too soon; if so,
 | 
				
			||||||
 | 
							// just wait and try again -- this is a special case of
 | 
				
			||||||
 | 
							// error that we handle differently, as you can see
 | 
				
			||||||
 | 
							if resp.StatusCode == http.StatusTooManyRequests {
 | 
				
			||||||
 | 
								log.Printf("[NOTICE] Sending diagnostics: we were too early; waiting %s before trying again", reply.NextUpdate)
 | 
				
			||||||
 | 
								time.Sleep(reply.NextUpdate)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							} else if resp.StatusCode >= 400 {
 | 
				
			||||||
 | 
								err = fmt.Errorf("diagnostics server returned status code %d", resp.StatusCode)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							break
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							// (remember, if there was an error, we return it
 | 
				
			||||||
 | 
							// below, so it will get logged if it's supposed to)
 | 
				
			||||||
 | 
							log.Println("[INFO] Sending diagnostics: success")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// even if there was an error after retrying, we should
 | 
				
			||||||
 | 
						// schedule the next update using our default update
 | 
				
			||||||
 | 
						// interval because the server might be healthy later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// schedule the next update (if this wasn't the last one and
 | 
				
			||||||
 | 
						// if the remote server didn't tell us to stop sending)
 | 
				
			||||||
 | 
						if !final && !reply.Stop {
 | 
				
			||||||
 | 
							updateTimerMu.Lock()
 | 
				
			||||||
 | 
							updateTimer = time.AfterFunc(reply.NextUpdate, func() {
 | 
				
			||||||
 | 
								logEmit(false)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							updateTimerMu.Unlock()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// makePayloadAndResetBuffer prepares a payload
 | 
				
			||||||
 | 
					// by emptying the collection buffer. It returns
 | 
				
			||||||
 | 
					// the bytes of the payload to send to the server.
 | 
				
			||||||
 | 
					// Since the buffer is reset by this, if the
 | 
				
			||||||
 | 
					// resulting byte slice is lost, the payload is
 | 
				
			||||||
 | 
					// gone with it.
 | 
				
			||||||
 | 
					func makePayloadAndResetBuffer() ([]byte, error) {
 | 
				
			||||||
 | 
						// make a local pointer to the buffer, then reset
 | 
				
			||||||
 | 
						// the buffer to an empty map to clear it out
 | 
				
			||||||
 | 
						bufferMu.Lock()
 | 
				
			||||||
 | 
						bufCopy := buffer
 | 
				
			||||||
 | 
						buffer = make(map[string]interface{})
 | 
				
			||||||
 | 
						bufferItemCount = 0
 | 
				
			||||||
 | 
						bufferMu.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// encode payload in preparation for transmission
 | 
				
			||||||
 | 
						payload := Payload{
 | 
				
			||||||
 | 
							InstanceID: instanceUUID.String(),
 | 
				
			||||||
 | 
							Timestamp:  time.Now().UTC(),
 | 
				
			||||||
 | 
							Data:       bufCopy,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return json.Marshal(payload)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Response contains the body of a response from the
 | 
				
			||||||
 | 
					// diagnostics server.
 | 
				
			||||||
 | 
					type Response struct {
 | 
				
			||||||
 | 
						// NextUpdate is how long to wait before the next update.
 | 
				
			||||||
 | 
						NextUpdate time.Duration `json:"next_update"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Stop instructs the diagnostics server to stop sending
 | 
				
			||||||
 | 
						// diagnostics. This would only be done under extenuating
 | 
				
			||||||
 | 
						// circumstances, but we are prepared for it nonetheless.
 | 
				
			||||||
 | 
						Stop bool `json:"stop,omitempty"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Error will be populated with an error message, if any.
 | 
				
			||||||
 | 
						// This field should be empty if the status code is < 400.
 | 
				
			||||||
 | 
						Error string `json:"error,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Payload is the data that gets sent to the diagnostics server.
 | 
				
			||||||
 | 
					type Payload struct {
 | 
				
			||||||
 | 
						// The universally unique ID of the instance
 | 
				
			||||||
 | 
						InstanceID string `json:"instance_id"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The UTC timestamp of the transmission
 | 
				
			||||||
 | 
						Timestamp time.Time `json:"timestamp"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The metrics
 | 
				
			||||||
 | 
						Data map[string]interface{} `json:"data,omitempty"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// httpClient should be used for HTTP requests. It
 | 
				
			||||||
 | 
					// is configured with a timeout for reliability.
 | 
				
			||||||
 | 
					var httpClient = http.Client{Timeout: 1 * time.Minute}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// buffer holds the data that we are building up to send.
 | 
				
			||||||
 | 
					var buffer = make(map[string]interface{})
 | 
				
			||||||
 | 
					var bufferItemCount = 0
 | 
				
			||||||
 | 
					var bufferMu sync.RWMutex // protects both the buffer and its count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// updating is used to ensure only one
 | 
				
			||||||
 | 
					// update happens at a time.
 | 
				
			||||||
 | 
					var updating bool
 | 
				
			||||||
 | 
					var updateMu sync.Mutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// updateTimer fires off the next update.
 | 
				
			||||||
 | 
					// If no update is scheduled, this is nil.
 | 
				
			||||||
 | 
					var updateTimer *time.Timer
 | 
				
			||||||
 | 
					var updateTimerMu sync.Mutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// instanceUUID is the ID of the current instance.
 | 
				
			||||||
 | 
					// This MUST be set to emit diagnostics.
 | 
				
			||||||
var instanceUUID uuid.UUID
 | 
					var instanceUUID uuid.UUID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// enabled indicates whether the package has
 | 
				
			||||||
 | 
					// been initialized and can be actively used.
 | 
				
			||||||
 | 
					var enabled bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						// endpoint is the base URL to remote diagnostics server;
 | 
				
			||||||
 | 
						// the instance ID will be appended to it.
 | 
				
			||||||
 | 
						endpoint = "http://localhost:8081/update/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// defaultUpdateInterval is how long to wait before emitting
 | 
				
			||||||
 | 
						// more diagnostic data. This value is only used if the
 | 
				
			||||||
 | 
						// client receives a nonsensical value, or doesn't send one
 | 
				
			||||||
 | 
						// at all, indicating a likely problem with the server. Thus,
 | 
				
			||||||
 | 
						// this value should be a long duration to help alleviate
 | 
				
			||||||
 | 
						// extra load on the server.
 | 
				
			||||||
 | 
						defaultUpdateInterval = 1 * time.Hour
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// maxBufferItems is the maximum number of items we'll allow
 | 
				
			||||||
 | 
						// in the buffer before we start dropping new ones, in a
 | 
				
			||||||
 | 
						// rough (simple) attempt to keep memory use under control.
 | 
				
			||||||
 | 
						maxBufferItems = 100000
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								vendor/github.com/klauspost/cpuid/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/klauspost/cpuid/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Copyright (c) 2015 Klaus Post
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					SOFTWARE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										1030
									
								
								vendor/github.com/klauspost/cpuid/cpuid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1030
									
								
								vendor/github.com/klauspost/cpuid/cpuid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										42
									
								
								vendor/github.com/klauspost/cpuid/cpuid_386.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/klauspost/cpuid/cpuid_386.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// +build 386,!gccgo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmCpuid(SB), 7, $0
 | 
				
			||||||
 | 
						XORL CX, CX
 | 
				
			||||||
 | 
						MOVL op+0(FP), AX
 | 
				
			||||||
 | 
						CPUID
 | 
				
			||||||
 | 
						MOVL AX, eax+4(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+8(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+12(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+16(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmCpuidex(SB), 7, $0
 | 
				
			||||||
 | 
						MOVL op+0(FP), AX
 | 
				
			||||||
 | 
						MOVL op2+4(FP), CX
 | 
				
			||||||
 | 
						CPUID
 | 
				
			||||||
 | 
						MOVL AX, eax+8(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+12(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+16(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+20(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func xgetbv(index uint32) (eax, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmXgetbv(SB), 7, $0
 | 
				
			||||||
 | 
						MOVL index+0(FP), CX
 | 
				
			||||||
 | 
						BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
 | 
				
			||||||
 | 
						MOVL AX, eax+4(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+8(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmRdtscpAsm(SB), 7, $0
 | 
				
			||||||
 | 
						BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
 | 
				
			||||||
 | 
						MOVL AX, eax+0(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+4(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+8(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+12(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
							
								
								
									
										42
									
								
								vendor/github.com/klauspost/cpuid/cpuid_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/klauspost/cpuid/cpuid_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//+build amd64,!gccgo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmCpuid(SB), 7, $0
 | 
				
			||||||
 | 
						XORQ CX, CX
 | 
				
			||||||
 | 
						MOVL op+0(FP), AX
 | 
				
			||||||
 | 
						CPUID
 | 
				
			||||||
 | 
						MOVL AX, eax+8(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+12(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+16(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+20(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmCpuidex(SB), 7, $0
 | 
				
			||||||
 | 
						MOVL op+0(FP), AX
 | 
				
			||||||
 | 
						MOVL op2+4(FP), CX
 | 
				
			||||||
 | 
						CPUID
 | 
				
			||||||
 | 
						MOVL AX, eax+8(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+12(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+16(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+20(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmXgetbv(index uint32) (eax, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmXgetbv(SB), 7, $0
 | 
				
			||||||
 | 
						MOVL index+0(FP), CX
 | 
				
			||||||
 | 
						BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
 | 
				
			||||||
 | 
						MOVL AX, eax+8(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+12(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmRdtscpAsm(SB), 7, $0
 | 
				
			||||||
 | 
						BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
 | 
				
			||||||
 | 
						MOVL AX, eax+0(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+4(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+8(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+12(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
							
								
								
									
										17
									
								
								vendor/github.com/klauspost/cpuid/detect_intel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/klauspost/cpuid/detect_intel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// +build 386,!gccgo amd64,!gccgo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package cpuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					func asmXgetbv(index uint32) (eax, edx uint32)
 | 
				
			||||||
 | 
					func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func initCPU() {
 | 
				
			||||||
 | 
						cpuid = asmCpuid
 | 
				
			||||||
 | 
						cpuidex = asmCpuidex
 | 
				
			||||||
 | 
						xgetbv = asmXgetbv
 | 
				
			||||||
 | 
						rdtscpAsm = asmRdtscpAsm
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								vendor/github.com/klauspost/cpuid/detect_ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/klauspost/cpuid/detect_ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// +build !amd64,!386 gccgo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package cpuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func initCPU() {
 | 
				
			||||||
 | 
						cpuid = func(op uint32) (eax, ebx, ecx, edx uint32) {
 | 
				
			||||||
 | 
							return 0, 0, 0, 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cpuidex = func(op, op2 uint32) (eax, ebx, ecx, edx uint32) {
 | 
				
			||||||
 | 
							return 0, 0, 0, 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xgetbv = func(index uint32) (eax, edx uint32) {
 | 
				
			||||||
 | 
							return 0, 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rdtscpAsm = func() (eax, ebx, ecx, edx uint32) {
 | 
				
			||||||
 | 
							return 0, 0, 0, 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										4
									
								
								vendor/github.com/klauspost/cpuid/generate.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/klauspost/cpuid/generate.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					package cpuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//go:generate go run private-gen.go
 | 
				
			||||||
 | 
					//go:generate gofmt -w ./private
 | 
				
			||||||
							
								
								
									
										476
									
								
								vendor/github.com/klauspost/cpuid/private-gen.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										476
									
								
								vendor/github.com/klauspost/cpuid/private-gen.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,476 @@
 | 
				
			|||||||
 | 
					// +build ignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"go/ast"
 | 
				
			||||||
 | 
						"go/parser"
 | 
				
			||||||
 | 
						"go/printer"
 | 
				
			||||||
 | 
						"go/token"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"unicode"
 | 
				
			||||||
 | 
						"unicode/utf8"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var inFiles = []string{"cpuid.go", "cpuid_test.go"}
 | 
				
			||||||
 | 
					var copyFiles = []string{"cpuid_amd64.s", "cpuid_386.s", "detect_ref.go", "detect_intel.go"}
 | 
				
			||||||
 | 
					var fileSet = token.NewFileSet()
 | 
				
			||||||
 | 
					var reWrites = []rewrite{
 | 
				
			||||||
 | 
						initRewrite("CPUInfo -> cpuInfo"),
 | 
				
			||||||
 | 
						initRewrite("Vendor -> vendor"),
 | 
				
			||||||
 | 
						initRewrite("Flags -> flags"),
 | 
				
			||||||
 | 
						initRewrite("Detect -> detect"),
 | 
				
			||||||
 | 
						initRewrite("CPU -> cpu"),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					var excludeNames = map[string]bool{"string": true, "join": true, "trim": true,
 | 
				
			||||||
 | 
						// cpuid_test.go
 | 
				
			||||||
 | 
						"t": true, "println": true, "logf": true, "log": true, "fatalf": true, "fatal": true,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var excludePrefixes = []string{"test", "benchmark"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
						Package := "private"
 | 
				
			||||||
 | 
						parserMode := parser.ParseComments
 | 
				
			||||||
 | 
						exported := make(map[string]rewrite)
 | 
				
			||||||
 | 
						for _, file := range inFiles {
 | 
				
			||||||
 | 
							in, err := os.Open(file)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatalf("opening input", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							src, err := ioutil.ReadAll(in)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatalf("reading input", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							astfile, err := parser.ParseFile(fileSet, file, src, parserMode)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatalf("parsing input", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, rw := range reWrites {
 | 
				
			||||||
 | 
								astfile = rw(astfile)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Inspect the AST and print all identifiers and literals.
 | 
				
			||||||
 | 
							var startDecl token.Pos
 | 
				
			||||||
 | 
							var endDecl token.Pos
 | 
				
			||||||
 | 
							ast.Inspect(astfile, func(n ast.Node) bool {
 | 
				
			||||||
 | 
								var s string
 | 
				
			||||||
 | 
								switch x := n.(type) {
 | 
				
			||||||
 | 
								case *ast.Ident:
 | 
				
			||||||
 | 
									if x.IsExported() {
 | 
				
			||||||
 | 
										t := strings.ToLower(x.Name)
 | 
				
			||||||
 | 
										for _, pre := range excludePrefixes {
 | 
				
			||||||
 | 
											if strings.HasPrefix(t, pre) {
 | 
				
			||||||
 | 
												return true
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if excludeNames[t] != true {
 | 
				
			||||||
 | 
											//if x.Pos() > startDecl && x.Pos() < endDecl {
 | 
				
			||||||
 | 
											exported[x.Name] = initRewrite(x.Name + " -> " + t)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case *ast.GenDecl:
 | 
				
			||||||
 | 
									if x.Tok == token.CONST && x.Lparen > 0 {
 | 
				
			||||||
 | 
										startDecl = x.Lparen
 | 
				
			||||||
 | 
										endDecl = x.Rparen
 | 
				
			||||||
 | 
										// fmt.Printf("Decl:%s -> %s\n", fileSet.Position(startDecl), fileSet.Position(endDecl))
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if s != "" {
 | 
				
			||||||
 | 
									fmt.Printf("%s:\t%s\n", fileSet.Position(n.Pos()), s)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, rw := range exported {
 | 
				
			||||||
 | 
								astfile = rw(astfile)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var buf bytes.Buffer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							printer.Fprint(&buf, fileSet, astfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Remove package documentation and insert information
 | 
				
			||||||
 | 
							s := buf.String()
 | 
				
			||||||
 | 
							ind := strings.Index(buf.String(), "\npackage cpuid")
 | 
				
			||||||
 | 
							s = s[ind:]
 | 
				
			||||||
 | 
							s = "// Generated, DO NOT EDIT,\n" +
 | 
				
			||||||
 | 
								"// but copy it to your own project and rename the package.\n" +
 | 
				
			||||||
 | 
								"// See more at http://github.com/klauspost/cpuid\n" +
 | 
				
			||||||
 | 
								s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							outputName := Package + string(os.PathSeparator) + file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = ioutil.WriteFile(outputName, []byte(s), 0644)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatalf("writing output: %s", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							log.Println("Generated", outputName)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, file := range copyFiles {
 | 
				
			||||||
 | 
							dst := ""
 | 
				
			||||||
 | 
							if strings.HasPrefix(file, "cpuid") {
 | 
				
			||||||
 | 
								dst = Package + string(os.PathSeparator) + file
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								dst = Package + string(os.PathSeparator) + "cpuid_" + file
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err := copyFile(file, dst)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Fatalf("copying file: %s", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							log.Println("Copied", dst)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CopyFile copies a file from src to dst. If src and dst files exist, and are
 | 
				
			||||||
 | 
					// the same, then return success. Copy the file contents from src to dst.
 | 
				
			||||||
 | 
					func copyFile(src, dst string) (err error) {
 | 
				
			||||||
 | 
						sfi, err := os.Stat(src)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !sfi.Mode().IsRegular() {
 | 
				
			||||||
 | 
							// cannot copy non-regular files (e.g., directories,
 | 
				
			||||||
 | 
							// symlinks, devices, etc.)
 | 
				
			||||||
 | 
							return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dfi, err := os.Stat(dst)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if !os.IsNotExist(err) {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if !(dfi.Mode().IsRegular()) {
 | 
				
			||||||
 | 
								return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if os.SameFile(sfi, dfi) {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = copyFileContents(src, dst)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// copyFileContents copies the contents of the file named src to the file named
 | 
				
			||||||
 | 
					// by dst. The file will be created if it does not already exist. If the
 | 
				
			||||||
 | 
					// destination file exists, all it's contents will be replaced by the contents
 | 
				
			||||||
 | 
					// of the source file.
 | 
				
			||||||
 | 
					func copyFileContents(src, dst string) (err error) {
 | 
				
			||||||
 | 
						in, err := os.Open(src)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer in.Close()
 | 
				
			||||||
 | 
						out, err := os.Create(dst)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							cerr := out.Close()
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								err = cerr
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
						if _, err = io.Copy(out, in); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = out.Sync()
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type rewrite func(*ast.File) *ast.File
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Mostly copied from gofmt
 | 
				
			||||||
 | 
					func initRewrite(rewriteRule string) rewrite {
 | 
				
			||||||
 | 
						f := strings.Split(rewriteRule, "->")
 | 
				
			||||||
 | 
						if len(f) != 2 {
 | 
				
			||||||
 | 
							fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
 | 
				
			||||||
 | 
							os.Exit(2)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pattern := parseExpr(f[0], "pattern")
 | 
				
			||||||
 | 
						replace := parseExpr(f[1], "replacement")
 | 
				
			||||||
 | 
						return func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// parseExpr parses s as an expression.
 | 
				
			||||||
 | 
					// It might make sense to expand this to allow statement patterns,
 | 
				
			||||||
 | 
					// but there are problems with preserving formatting and also
 | 
				
			||||||
 | 
					// with what a wildcard for a statement looks like.
 | 
				
			||||||
 | 
					func parseExpr(s, what string) ast.Expr {
 | 
				
			||||||
 | 
						x, err := parser.ParseExpr(s)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							fmt.Fprintf(os.Stderr, "parsing %s %s at %s\n", what, s, err)
 | 
				
			||||||
 | 
							os.Exit(2)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return x
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Keep this function for debugging.
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					func dump(msg string, val reflect.Value) {
 | 
				
			||||||
 | 
						fmt.Printf("%s:\n", msg)
 | 
				
			||||||
 | 
						ast.Print(fileSet, val.Interface())
 | 
				
			||||||
 | 
						fmt.Println()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
 | 
				
			||||||
 | 
					func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
 | 
				
			||||||
 | 
						cmap := ast.NewCommentMap(fileSet, p, p.Comments)
 | 
				
			||||||
 | 
						m := make(map[string]reflect.Value)
 | 
				
			||||||
 | 
						pat := reflect.ValueOf(pattern)
 | 
				
			||||||
 | 
						repl := reflect.ValueOf(replace)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var rewriteVal func(val reflect.Value) reflect.Value
 | 
				
			||||||
 | 
						rewriteVal = func(val reflect.Value) reflect.Value {
 | 
				
			||||||
 | 
							// don't bother if val is invalid to start with
 | 
				
			||||||
 | 
							if !val.IsValid() {
 | 
				
			||||||
 | 
								return reflect.Value{}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for k := range m {
 | 
				
			||||||
 | 
								delete(m, k)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							val = apply(rewriteVal, val)
 | 
				
			||||||
 | 
							if match(m, pat, val) {
 | 
				
			||||||
 | 
								val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return val
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File)
 | 
				
			||||||
 | 
						r.Comments = cmap.Filter(r).Comments() // recreate comments list
 | 
				
			||||||
 | 
						return r
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y.
 | 
				
			||||||
 | 
					func set(x, y reflect.Value) {
 | 
				
			||||||
 | 
						// don't bother if x cannot be set or y is invalid
 | 
				
			||||||
 | 
						if !x.CanSet() || !y.IsValid() {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							if x := recover(); x != nil {
 | 
				
			||||||
 | 
								if s, ok := x.(string); ok &&
 | 
				
			||||||
 | 
									(strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) {
 | 
				
			||||||
 | 
									// x cannot be set to y - ignore this rewrite
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								panic(x)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
						x.Set(y)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Values/types for special cases.
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
 | 
				
			||||||
 | 
						scopePtrNil  = reflect.ValueOf((*ast.Scope)(nil))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						identType     = reflect.TypeOf((*ast.Ident)(nil))
 | 
				
			||||||
 | 
						objectPtrType = reflect.TypeOf((*ast.Object)(nil))
 | 
				
			||||||
 | 
						positionType  = reflect.TypeOf(token.NoPos)
 | 
				
			||||||
 | 
						callExprType  = reflect.TypeOf((*ast.CallExpr)(nil))
 | 
				
			||||||
 | 
						scopePtrType  = reflect.TypeOf((*ast.Scope)(nil))
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// apply replaces each AST field x in val with f(x), returning val.
 | 
				
			||||||
 | 
					// To avoid extra conversions, f operates on the reflect.Value form.
 | 
				
			||||||
 | 
					func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
 | 
				
			||||||
 | 
						if !val.IsValid() {
 | 
				
			||||||
 | 
							return reflect.Value{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// *ast.Objects introduce cycles and are likely incorrect after
 | 
				
			||||||
 | 
						// rewrite; don't follow them but replace with nil instead
 | 
				
			||||||
 | 
						if val.Type() == objectPtrType {
 | 
				
			||||||
 | 
							return objectPtrNil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// similarly for scopes: they are likely incorrect after a rewrite;
 | 
				
			||||||
 | 
						// replace them with nil
 | 
				
			||||||
 | 
						if val.Type() == scopePtrType {
 | 
				
			||||||
 | 
							return scopePtrNil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch v := reflect.Indirect(val); v.Kind() {
 | 
				
			||||||
 | 
						case reflect.Slice:
 | 
				
			||||||
 | 
							for i := 0; i < v.Len(); i++ {
 | 
				
			||||||
 | 
								e := v.Index(i)
 | 
				
			||||||
 | 
								set(e, f(e))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case reflect.Struct:
 | 
				
			||||||
 | 
							for i := 0; i < v.NumField(); i++ {
 | 
				
			||||||
 | 
								e := v.Field(i)
 | 
				
			||||||
 | 
								set(e, f(e))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case reflect.Interface:
 | 
				
			||||||
 | 
							e := v.Elem()
 | 
				
			||||||
 | 
							set(v, f(e))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return val
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isWildcard(s string) bool {
 | 
				
			||||||
 | 
						rune, size := utf8.DecodeRuneInString(s)
 | 
				
			||||||
 | 
						return size == len(s) && unicode.IsLower(rune)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// match returns true if pattern matches val,
 | 
				
			||||||
 | 
					// recording wildcard submatches in m.
 | 
				
			||||||
 | 
					// If m == nil, match checks whether pattern == val.
 | 
				
			||||||
 | 
					func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
 | 
				
			||||||
 | 
						// Wildcard matches any expression.  If it appears multiple
 | 
				
			||||||
 | 
						// times in the pattern, it must match the same expression
 | 
				
			||||||
 | 
						// each time.
 | 
				
			||||||
 | 
						if m != nil && pattern.IsValid() && pattern.Type() == identType {
 | 
				
			||||||
 | 
							name := pattern.Interface().(*ast.Ident).Name
 | 
				
			||||||
 | 
							if isWildcard(name) && val.IsValid() {
 | 
				
			||||||
 | 
								// wildcards only match valid (non-nil) expressions.
 | 
				
			||||||
 | 
								if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() {
 | 
				
			||||||
 | 
									if old, ok := m[name]; ok {
 | 
				
			||||||
 | 
										return match(nil, old, val)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									m[name] = val
 | 
				
			||||||
 | 
									return true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Otherwise, pattern and val must match recursively.
 | 
				
			||||||
 | 
						if !pattern.IsValid() || !val.IsValid() {
 | 
				
			||||||
 | 
							return !pattern.IsValid() && !val.IsValid()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if pattern.Type() != val.Type() {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Special cases.
 | 
				
			||||||
 | 
						switch pattern.Type() {
 | 
				
			||||||
 | 
						case identType:
 | 
				
			||||||
 | 
							// For identifiers, only the names need to match
 | 
				
			||||||
 | 
							// (and none of the other *ast.Object information).
 | 
				
			||||||
 | 
							// This is a common case, handle it all here instead
 | 
				
			||||||
 | 
							// of recursing down any further via reflection.
 | 
				
			||||||
 | 
							p := pattern.Interface().(*ast.Ident)
 | 
				
			||||||
 | 
							v := val.Interface().(*ast.Ident)
 | 
				
			||||||
 | 
							return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
 | 
				
			||||||
 | 
						case objectPtrType, positionType:
 | 
				
			||||||
 | 
							// object pointers and token positions always match
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
						case callExprType:
 | 
				
			||||||
 | 
							// For calls, the Ellipsis fields (token.Position) must
 | 
				
			||||||
 | 
							// match since that is how f(x) and f(x...) are different.
 | 
				
			||||||
 | 
							// Check them here but fall through for the remaining fields.
 | 
				
			||||||
 | 
							p := pattern.Interface().(*ast.CallExpr)
 | 
				
			||||||
 | 
							v := val.Interface().(*ast.CallExpr)
 | 
				
			||||||
 | 
							if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p := reflect.Indirect(pattern)
 | 
				
			||||||
 | 
						v := reflect.Indirect(val)
 | 
				
			||||||
 | 
						if !p.IsValid() || !v.IsValid() {
 | 
				
			||||||
 | 
							return !p.IsValid() && !v.IsValid()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch p.Kind() {
 | 
				
			||||||
 | 
						case reflect.Slice:
 | 
				
			||||||
 | 
							if p.Len() != v.Len() {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for i := 0; i < p.Len(); i++ {
 | 
				
			||||||
 | 
								if !match(m, p.Index(i), v.Index(i)) {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case reflect.Struct:
 | 
				
			||||||
 | 
							for i := 0; i < p.NumField(); i++ {
 | 
				
			||||||
 | 
								if !match(m, p.Field(i), v.Field(i)) {
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case reflect.Interface:
 | 
				
			||||||
 | 
							return match(m, p.Elem(), v.Elem())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Handle token integers, etc.
 | 
				
			||||||
 | 
						return p.Interface() == v.Interface()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// subst returns a copy of pattern with values from m substituted in place
 | 
				
			||||||
 | 
					// of wildcards and pos used as the position of tokens from the pattern.
 | 
				
			||||||
 | 
					// if m == nil, subst returns a copy of pattern and doesn't change the line
 | 
				
			||||||
 | 
					// number information.
 | 
				
			||||||
 | 
					func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
 | 
				
			||||||
 | 
						if !pattern.IsValid() {
 | 
				
			||||||
 | 
							return reflect.Value{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Wildcard gets replaced with map value.
 | 
				
			||||||
 | 
						if m != nil && pattern.Type() == identType {
 | 
				
			||||||
 | 
							name := pattern.Interface().(*ast.Ident).Name
 | 
				
			||||||
 | 
							if isWildcard(name) {
 | 
				
			||||||
 | 
								if old, ok := m[name]; ok {
 | 
				
			||||||
 | 
									return subst(nil, old, reflect.Value{})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if pos.IsValid() && pattern.Type() == positionType {
 | 
				
			||||||
 | 
							// use new position only if old position was valid in the first place
 | 
				
			||||||
 | 
							if old := pattern.Interface().(token.Pos); !old.IsValid() {
 | 
				
			||||||
 | 
								return pattern
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return pos
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Otherwise copy.
 | 
				
			||||||
 | 
						switch p := pattern; p.Kind() {
 | 
				
			||||||
 | 
						case reflect.Slice:
 | 
				
			||||||
 | 
							v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
 | 
				
			||||||
 | 
							for i := 0; i < p.Len(); i++ {
 | 
				
			||||||
 | 
								v.Index(i).Set(subst(m, p.Index(i), pos))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case reflect.Struct:
 | 
				
			||||||
 | 
							v := reflect.New(p.Type()).Elem()
 | 
				
			||||||
 | 
							for i := 0; i < p.NumField(); i++ {
 | 
				
			||||||
 | 
								v.Field(i).Set(subst(m, p.Field(i), pos))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case reflect.Ptr:
 | 
				
			||||||
 | 
							v := reflect.New(p.Type()).Elem()
 | 
				
			||||||
 | 
							if elem := p.Elem(); elem.IsValid() {
 | 
				
			||||||
 | 
								v.Set(subst(m, elem, pos).Addr())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case reflect.Interface:
 | 
				
			||||||
 | 
							v := reflect.New(p.Type()).Elem()
 | 
				
			||||||
 | 
							if elem := p.Elem(); elem.IsValid() {
 | 
				
			||||||
 | 
								v.Set(subst(m, elem, pos))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return v
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pattern
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1024
									
								
								vendor/github.com/klauspost/cpuid/private/cpuid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1024
									
								
								vendor/github.com/klauspost/cpuid/private/cpuid.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										42
									
								
								vendor/github.com/klauspost/cpuid/private/cpuid_386.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/klauspost/cpuid/private/cpuid_386.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// +build 386,!gccgo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmCpuid(SB), 7, $0
 | 
				
			||||||
 | 
						XORL CX, CX
 | 
				
			||||||
 | 
						MOVL op+0(FP), AX
 | 
				
			||||||
 | 
						CPUID
 | 
				
			||||||
 | 
						MOVL AX, eax+4(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+8(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+12(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+16(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmCpuidex(SB), 7, $0
 | 
				
			||||||
 | 
						MOVL op+0(FP), AX
 | 
				
			||||||
 | 
						MOVL op2+4(FP), CX
 | 
				
			||||||
 | 
						CPUID
 | 
				
			||||||
 | 
						MOVL AX, eax+8(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+12(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+16(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+20(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func xgetbv(index uint32) (eax, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmXgetbv(SB), 7, $0
 | 
				
			||||||
 | 
						MOVL index+0(FP), CX
 | 
				
			||||||
 | 
						BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
 | 
				
			||||||
 | 
						MOVL AX, eax+4(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+8(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmRdtscpAsm(SB), 7, $0
 | 
				
			||||||
 | 
						BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
 | 
				
			||||||
 | 
						MOVL AX, eax+0(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+4(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+8(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+12(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
							
								
								
									
										42
									
								
								vendor/github.com/klauspost/cpuid/private/cpuid_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/klauspost/cpuid/private/cpuid_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//+build amd64,!gccgo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmCpuid(SB), 7, $0
 | 
				
			||||||
 | 
						XORQ CX, CX
 | 
				
			||||||
 | 
						MOVL op+0(FP), AX
 | 
				
			||||||
 | 
						CPUID
 | 
				
			||||||
 | 
						MOVL AX, eax+8(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+12(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+16(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+20(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmCpuidex(SB), 7, $0
 | 
				
			||||||
 | 
						MOVL op+0(FP), AX
 | 
				
			||||||
 | 
						MOVL op2+4(FP), CX
 | 
				
			||||||
 | 
						CPUID
 | 
				
			||||||
 | 
						MOVL AX, eax+8(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+12(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+16(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+20(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmXgetbv(index uint32) (eax, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmXgetbv(SB), 7, $0
 | 
				
			||||||
 | 
						MOVL index+0(FP), CX
 | 
				
			||||||
 | 
						BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV
 | 
				
			||||||
 | 
						MOVL AX, eax+8(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+12(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					TEXT ·asmRdtscpAsm(SB), 7, $0
 | 
				
			||||||
 | 
						BYTE $0x0F; BYTE $0x01; BYTE $0xF9 // RDTSCP
 | 
				
			||||||
 | 
						MOVL AX, eax+0(FP)
 | 
				
			||||||
 | 
						MOVL BX, ebx+4(FP)
 | 
				
			||||||
 | 
						MOVL CX, ecx+8(FP)
 | 
				
			||||||
 | 
						MOVL DX, edx+12(FP)
 | 
				
			||||||
 | 
						RET
 | 
				
			||||||
							
								
								
									
										17
									
								
								vendor/github.com/klauspost/cpuid/private/cpuid_detect_intel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/klauspost/cpuid/private/cpuid_detect_intel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// +build 386,!gccgo amd64,!gccgo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package cpuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					func asmXgetbv(index uint32) (eax, edx uint32)
 | 
				
			||||||
 | 
					func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func initCPU() {
 | 
				
			||||||
 | 
						cpuid = asmCpuid
 | 
				
			||||||
 | 
						cpuidex = asmCpuidex
 | 
				
			||||||
 | 
						xgetbv = asmXgetbv
 | 
				
			||||||
 | 
						rdtscpAsm = asmRdtscpAsm
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								vendor/github.com/klauspost/cpuid/private/cpuid_detect_ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/klauspost/cpuid/private/cpuid_detect_ref.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// +build !amd64,!386 gccgo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package cpuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func initCPU() {
 | 
				
			||||||
 | 
						cpuid = func(op uint32) (eax, ebx, ecx, edx uint32) {
 | 
				
			||||||
 | 
							return 0, 0, 0, 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cpuidex = func(op, op2 uint32) (eax, ebx, ecx, edx uint32) {
 | 
				
			||||||
 | 
							return 0, 0, 0, 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xgetbv = func(index uint32) (eax, edx uint32) {
 | 
				
			||||||
 | 
							return 0, 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rdtscpAsm = func() (eax, ebx, ecx, edx uint32) {
 | 
				
			||||||
 | 
							return 0, 0, 0, 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								vendor/manifest
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/manifest
									
									
									
									
										vendored
									
									
								
							@ -117,6 +117,14 @@
 | 
				
			|||||||
			"path": "/basic",
 | 
								"path": "/basic",
 | 
				
			||||||
			"notests": true
 | 
								"notests": true
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"importpath": "github.com/klauspost/cpuid",
 | 
				
			||||||
 | 
								"repository": "https://github.com/klauspost/cpuid",
 | 
				
			||||||
 | 
								"vcs": "git",
 | 
				
			||||||
 | 
								"revision": "ae832f27941af41db13bd6d8efd2493e3b22415a",
 | 
				
			||||||
 | 
								"branch": "master",
 | 
				
			||||||
 | 
								"notests": true
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"importpath": "github.com/lucas-clemente/aes12",
 | 
								"importpath": "github.com/lucas-clemente/aes12",
 | 
				
			||||||
			"repository": "https://github.com/lucas-clemente/aes12",
 | 
								"repository": "https://github.com/lucas-clemente/aes12",
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user