| @@ -0,0 +1,15 @@ | ||
| +# mmvdump [](https://godoc.org/github.com/performancecopilot/speed/mmvdump) | ||
| + | ||
| +Package mmvdump implements a go port of the C mmvdump utility included in PCP Core | ||
| + | ||
| +https://github.com/performancecopilot/pcp/blob/master/src/pmdas/mmv/mmvdump.c | ||
| + | ||
| +It has been written for maximum portability with the C equivalent, without having to use cgo or any other ninja stuff | ||
| + | ||
| +the main difference is that the reader is separate from the cli with the reading primarily implemented in mmvdump.go while the cli is implemented in cmd/mmvdump | ||
| + | ||
| +the cli application is completely go gettable and outputs the same things, in mostly the same way as the C cli app, to try it out, | ||
| + | ||
| +``` | ||
| +go get github.com/performancecopilot/speed/mmvdump/cmd/mmvdump | ||
| +``` |
| @@ -0,0 +1,196 @@ | ||
| +package main | ||
| + | ||
| +import ( | ||
| + "flag" | ||
| + "fmt" | ||
| + "os" | ||
| + | ||
| + "github.com/performancecopilot/speed/mmvdump" | ||
| +) | ||
| + | ||
| +var ( | ||
| + header *mmvdump.Header | ||
| + tocs []*mmvdump.Toc | ||
| + metrics map[uint64]*mmvdump.Metric | ||
| + values map[uint64]*mmvdump.Value | ||
| + instances map[uint64]*mmvdump.Instance | ||
| + indoms map[uint64]*mmvdump.InstanceDomain | ||
| + strings map[uint64]*mmvdump.String | ||
| +) | ||
| + | ||
| +func printInstance(offset uint64) { | ||
| + i := instances[offset] | ||
| + indom := indoms[i.Indom] | ||
| + fmt.Printf("\t[%v/%v] instance = [%v/%v]\n", indom.Serial, offset, i.Internal, string(i.External[:])) | ||
| +} | ||
| + | ||
| +func printInstanceDomain(offset uint64) { | ||
| + indom := indoms[offset] | ||
| + fmt.Printf("\t[%v/%v] %d instances, starting at offset %d\n", indom.Serial, offset, indom.Count, indom.Offset) | ||
| + | ||
| + if indom.Shorttext == 0 { | ||
| + fmt.Printf("\t\t(no shorttext)\n") | ||
| + } else { | ||
| + fmt.Printf("\t\tshorttext=%v\n", string(strings[indom.Shorttext].Payload[:])) | ||
| + } | ||
| + | ||
| + if indom.Longtext == 0 { | ||
| + fmt.Printf("\t\t(no longtext)\n") | ||
| + } else { | ||
| + fmt.Printf("\t\tlongtext=%v\n", string(strings[indom.Longtext].Payload[:])) | ||
| + } | ||
| +} | ||
| + | ||
| +func printMetric(offset uint64) { | ||
| + m := metrics[offset] | ||
| + | ||
| + fmt.Printf("\t[%v/%v] %v\n", m.Item, offset, string(m.Name[:])) | ||
| + fmt.Printf("\t\ttype=%v (0x%x), sem=%v (0x%x), pad=0x%x\n", m.Typ, int(m.Typ), m.Sem, int(m.Sem), m.Padding) | ||
| + fmt.Printf("\t\tunits=%v\n", m.Unit) | ||
| + | ||
| + if m.Indom == mmvdump.NoIndom { | ||
| + fmt.Printf("\t\t(no indom)\n") | ||
| + } else { | ||
| + fmt.Printf("\t\tindom=%d\n", m.Indom) | ||
| + } | ||
| + | ||
| + if m.Shorttext == 0 { | ||
| + fmt.Printf("\t\t(no shorttext)\n") | ||
| + } else { | ||
| + fmt.Printf("\t\tshorttext=%v\n", string(strings[m.Shorttext].Payload[:])) | ||
| + } | ||
| + | ||
| + if m.Longtext == 0 { | ||
| + fmt.Printf("\t\t(no longtext)\n") | ||
| + } else { | ||
| + fmt.Printf("\t\tlongtext=%v\n", string(strings[m.Longtext].Payload[:])) | ||
| + } | ||
| +} | ||
| + | ||
| +func printValue(offset uint64) { | ||
| + v := values[offset] | ||
| + m := metrics[v.Metric] | ||
| + | ||
| + fmt.Printf("\t[%v/%v] %v", m.Item, offset, string(m.Name[:])) | ||
| + | ||
| + var ( | ||
| + a interface{} | ||
| + err error | ||
| + ) | ||
| + | ||
| + if m.Typ != mmvdump.StringType { | ||
| + a, err = mmvdump.FixedVal(v.Val, m.Typ) | ||
| + } else { | ||
| + v, ok := strings[uint64(v.Extra)] | ||
| + if !ok { | ||
| + panic("invalid string address") | ||
| + } | ||
| + a = string(v.Payload[:]) | ||
| + } | ||
| + | ||
| + if m.Indom != mmvdump.NoIndom { | ||
| + i := instances[v.Instance] | ||
| + fmt.Printf("[%d or \"%s\"]", i.Internal, string(i.External[:])) | ||
| + } | ||
| + | ||
| + if err != nil { | ||
| + panic(err) | ||
| + } | ||
| + | ||
| + fmt.Printf(" = %v\n", a) | ||
| +} | ||
| + | ||
| +func printString(offset uint64) { | ||
| + fmt.Printf("\t[%v] %v\n", offset, string(strings[offset].Payload[:])) | ||
| +} | ||
| + | ||
| +func data(file string) []byte { | ||
| + f, err := os.Open(file) | ||
| + if err != nil { | ||
| + panic(err) | ||
| + } | ||
| + | ||
| + fi, err := os.Stat(file) | ||
| + if err != nil { | ||
| + panic(err) | ||
| + } | ||
| + | ||
| + len := fi.Size() | ||
| + data := make([]byte, len) | ||
| + | ||
| + _, err = f.Read(data) | ||
| + if err != nil { | ||
| + panic(err) | ||
| + } | ||
| + | ||
| + return data | ||
| +} | ||
| + | ||
| +func main() { | ||
| + flag.Parse() | ||
| + | ||
| + if flag.NArg() < 1 { | ||
| + fmt.Println("usage: mmvdump <file>") | ||
| + return | ||
| + } | ||
| + | ||
| + file := flag.Arg(0) | ||
| + d := data(file) | ||
| + | ||
| + var err error | ||
| + header, tocs, metrics, values, instances, indoms, strings, err = mmvdump.Dump(d) | ||
| + if err != nil { | ||
| + panic(err) | ||
| + } | ||
| + | ||
| + fmt.Printf(` | ||
| +File = %v | ||
| +Version = %v | ||
| +Generated = %v | ||
| +Toc Count = %v | ||
| +Cluster = %v | ||
| +Process = %v | ||
| +Flags = 0x%x | ||
| + | ||
| +`, file, header.Version, header.G1, header.Toc, header.Cluster, header.Process, int(header.Flag)) | ||
| + | ||
| + toff := mmvdump.HeaderLength | ||
| + var ( | ||
| + itemtype string | ||
| + itemsize uint64 | ||
| + printItem func(uint64) | ||
| + ) | ||
| + | ||
| + for ti, toc := range tocs { | ||
| + switch toc.Type { | ||
| + case mmvdump.TocInstances: | ||
| + itemtype = "instances" | ||
| + itemsize = mmvdump.InstanceLength | ||
| + printItem = printInstance | ||
| + case mmvdump.TocIndoms: | ||
| + itemtype = "indoms" | ||
| + itemsize = mmvdump.InstanceDomainLength | ||
| + printItem = printInstanceDomain | ||
| + case mmvdump.TocMetrics: | ||
| + itemtype = "metric" | ||
| + itemsize = mmvdump.MetricLength | ||
| + printItem = printMetric | ||
| + case mmvdump.TocValues: | ||
| + itemtype = "values" | ||
| + itemsize = mmvdump.ValueLength | ||
| + printItem = printValue | ||
| + case mmvdump.TocStrings: | ||
| + itemtype = "strings" | ||
| + itemsize = mmvdump.StringLength | ||
| + printItem = printString | ||
| + } | ||
| + | ||
| + fmt.Printf("TOC[%v], offset: %v, %v offset: %v (%v entries)\n", ti, toff, itemtype, toc.Offset, toc.Count) | ||
| + for i, offset := int32(0), toc.Offset; i < toc.Count; i, offset = i+1, offset+itemsize { | ||
| + printItem(offset) | ||
| + } | ||
| + fmt.Println() | ||
| + | ||
| + toff += mmvdump.TocLength | ||
| + } | ||
| +} |
| @@ -0,0 +1,350 @@ | ||
| +// Package mmvdump implements a go port of the C mmvdump utility included in PCP Core | ||
| +// | ||
| +// https://github.com/performancecopilot/pcp/blob/master/src/pmdas/mmv/mmvdump.c | ||
| +// | ||
| +// It has been written for maximum portability with the C equivalent, without having to use cgo or any other ninja stuff | ||
| +// | ||
| +// the main difference is that the reader is separate from the cli with the reading primarily implemented in mmvdump.go while the cli is implemented in cmd/mmvdump | ||
| +// | ||
| +// the cli application is completely go gettable and outputs the same things, in mostly the same way as the C cli app, to try it out, | ||
| +// | ||
| +// ``` | ||
| +// go get github.com/performancecopilot/speed/mmvdump/cmd/mmvdump | ||
| +// ``` | ||
| +package mmvdump | ||
| + | ||
| +import ( | ||
| + "errors" | ||
| + "fmt" | ||
| + "math" | ||
| + "sync" | ||
| + "unsafe" | ||
| +) | ||
| + | ||
| +func readHeader(data []byte) (*Header, error) { | ||
| + if uint64(len(data)) < HeaderLength { | ||
| + return nil, errors.New("file too small to contain a valid Header") | ||
| + } | ||
| + | ||
| + header := (*Header)(unsafe.Pointer(&data[0])) | ||
| + | ||
| + if m := header.Magic[:3]; string(m) != "MMV" { | ||
| + return nil, fmt.Errorf("Bad Magic: %v", string(m)) | ||
| + } | ||
| + | ||
| + if header.G1 != header.G2 { | ||
| + return nil, fmt.Errorf("Mismatched version numbers, %v and %v", header.G1, header.G2) | ||
| + } | ||
| + | ||
| + return header, nil | ||
| +} | ||
| + | ||
| +func readToc(data []byte, offset uint64) (*Toc, error) { | ||
| + if uint64(len(data)) < offset+TocLength { | ||
| + return nil, errors.New("Incomplete/Partially Written TOC") | ||
| + } | ||
| + | ||
| + return (*Toc)(unsafe.Pointer(&data[offset])), nil | ||
| +} | ||
| + | ||
| +func readInstance(data []byte, offset uint64) (*Instance, error) { | ||
| + if uint64(len(data)) < offset+InstanceLength { | ||
| + return nil, errors.New("Incomplete/Partially Written Instance") | ||
| + } | ||
| + | ||
| + return (*Instance)(unsafe.Pointer(&data[offset])), nil | ||
| +} | ||
| + | ||
| +func readInstanceDomain(data []byte, offset uint64) (*InstanceDomain, error) { | ||
| + if uint64(len(data)) < offset+InstanceDomainLength { | ||
| + return nil, errors.New("Incomplete/Partially Written InstanceDomain") | ||
| + } | ||
| + | ||
| + return (*InstanceDomain)(unsafe.Pointer(&data[offset])), nil | ||
| +} | ||
| + | ||
| +func readMetric(data []byte, offset uint64) (*Metric, error) { | ||
| + if uint64(len(data)) < offset+MetricLength { | ||
| + return nil, errors.New("Incomplete/Partially Written Metric") | ||
| + } | ||
| + | ||
| + return (*Metric)(unsafe.Pointer(&data[offset])), nil | ||
| +} | ||
| + | ||
| +func readValue(data []byte, offset uint64) (*Value, error) { | ||
| + if uint64(len(data)) < offset+ValueLength { | ||
| + return nil, errors.New("Incomplete/Partially Written Value") | ||
| + } | ||
| + | ||
| + return (*Value)(unsafe.Pointer(&data[offset])), nil | ||
| +} | ||
| + | ||
| +func readString(data []byte, offset uint64) (*String, error) { | ||
| + if uint64(len(data)) < offset+StringLength { | ||
| + return nil, errors.New("Incomplete/Partially Written String") | ||
| + } | ||
| + | ||
| + return (*String)(unsafe.Pointer(&data[offset])), nil | ||
| +} | ||
| + | ||
| +func readTocs(data []byte, count int32) ([]*Toc, error) { | ||
| + tocs := make([]*Toc, count) | ||
| + | ||
| + for i := int32(0); i < count; i++ { | ||
| + t, err := readToc(data, HeaderLength+uint64(i)*TocLength) | ||
| + if err != nil { | ||
| + return nil, err | ||
| + } | ||
| + tocs[i] = t | ||
| + } | ||
| + | ||
| + return tocs, nil | ||
| +} | ||
| + | ||
| +func readInstances(data []byte, offset uint64, count int32) (map[uint64]*Instance, error) { | ||
| + var wg sync.WaitGroup | ||
| + wg.Add(int(count)) | ||
| + | ||
| + instances := make(map[uint64]*Instance) | ||
| + | ||
| + var ( | ||
| + instance *Instance | ||
| + err error | ||
| + m sync.Mutex | ||
| + ) | ||
| + | ||
| + for i := int32(0); i < count; i, offset = i+1, offset+InstanceLength { | ||
| + go func(offset uint64) { | ||
| + instance, err = readInstance(data, offset) | ||
| + if err == nil { | ||
| + m.Lock() | ||
| + instances[offset] = instance | ||
| + m.Unlock() | ||
| + } | ||
| + wg.Done() | ||
| + }(offset) | ||
| + } | ||
| + | ||
| + wg.Wait() | ||
| + | ||
| + if err != nil { | ||
| + return nil, err | ||
| + } | ||
| + | ||
| + return instances, nil | ||
| +} | ||
| + | ||
| +func readInstanceDomains(data []byte, offset uint64, count int32) (map[uint64]*InstanceDomain, error) { | ||
| + var wg sync.WaitGroup | ||
| + wg.Add(int(count)) | ||
| + | ||
| + indoms := make(map[uint64]*InstanceDomain) | ||
| + | ||
| + var ( | ||
| + indom *InstanceDomain | ||
| + err error | ||
| + m sync.Mutex | ||
| + ) | ||
| + | ||
| + for i := int32(0); i < count; i, offset = i+1, offset+InstanceDomainLength { | ||
| + go func(offset uint64) { | ||
| + indom, err = readInstanceDomain(data, offset) | ||
| + if err == nil { | ||
| + m.Lock() | ||
| + indoms[offset] = indom | ||
| + m.Unlock() | ||
| + } | ||
| + wg.Done() | ||
| + }(offset) | ||
| + } | ||
| + | ||
| + wg.Wait() | ||
| + | ||
| + if err != nil { | ||
| + return nil, err | ||
| + } | ||
| + | ||
| + return indoms, nil | ||
| +} | ||
| + | ||
| +func readMetrics(data []byte, offset uint64, count int32) (map[uint64]*Metric, error) { | ||
| + var wg sync.WaitGroup | ||
| + wg.Add(int(count)) | ||
| + | ||
| + metrics := make(map[uint64]*Metric) | ||
| + | ||
| + var ( | ||
| + metric *Metric | ||
| + err error | ||
| + m sync.Mutex | ||
| + ) | ||
| + | ||
| + for i := int32(0); i < count; i, offset = i+1, offset+MetricLength { | ||
| + go func(offset uint64) { | ||
| + metric, err = readMetric(data, offset) | ||
| + if err == nil { | ||
| + m.Lock() | ||
| + metrics[offset] = metric | ||
| + m.Unlock() | ||
| + } | ||
| + wg.Done() | ||
| + }(offset) | ||
| + } | ||
| + | ||
| + wg.Wait() | ||
| + | ||
| + if err != nil { | ||
| + return nil, err | ||
| + } | ||
| + | ||
| + return metrics, nil | ||
| +} | ||
| + | ||
| +func readValues(data []byte, offset uint64, count int32) (map[uint64]*Value, error) { | ||
| + var wg sync.WaitGroup | ||
| + wg.Add(int(count)) | ||
| + | ||
| + values := make(map[uint64]*Value) | ||
| + | ||
| + var ( | ||
| + value *Value | ||
| + err error | ||
| + m sync.Mutex | ||
| + ) | ||
| + | ||
| + for i := int32(0); i < count; i, offset = i+1, offset+ValueLength { | ||
| + go func(offset uint64) { | ||
| + value, err = readValue(data, offset) | ||
| + if err == nil { | ||
| + m.Lock() | ||
| + values[offset] = value | ||
| + m.Unlock() | ||
| + } | ||
| + wg.Done() | ||
| + }(offset) | ||
| + } | ||
| + | ||
| + wg.Wait() | ||
| + | ||
| + if err != nil { | ||
| + return nil, err | ||
| + } | ||
| + | ||
| + return values, nil | ||
| +} | ||
| + | ||
| +func readStrings(data []byte, offset uint64, count int32) (map[uint64]*String, error) { | ||
| + var wg sync.WaitGroup | ||
| + wg.Add(int(count)) | ||
| + | ||
| + strings := make(map[uint64]*String) | ||
| + | ||
| + var ( | ||
| + str *String | ||
| + err error | ||
| + m sync.Mutex | ||
| + ) | ||
| + | ||
| + for i := int32(0); i < count; i, offset = i+1, offset+StringLength { | ||
| + go func(offset uint64) { | ||
| + str, err = readString(data, offset) | ||
| + if err == nil { | ||
| + m.Lock() | ||
| + strings[offset] = str | ||
| + m.Unlock() | ||
| + } | ||
| + wg.Done() | ||
| + }(offset) | ||
| + } | ||
| + | ||
| + wg.Wait() | ||
| + | ||
| + if err != nil { | ||
| + return nil, err | ||
| + } | ||
| + | ||
| + return strings, nil | ||
| +} | ||
| + | ||
| +// Dump creates a data dump from the passed data | ||
| +func Dump(data []byte) ( | ||
| + h *Header, | ||
| + tocs []*Toc, | ||
| + metrics map[uint64]*Metric, | ||
| + values map[uint64]*Value, | ||
| + instances map[uint64]*Instance, | ||
| + indoms map[uint64]*InstanceDomain, | ||
| + strings map[uint64]*String, | ||
| + err error, | ||
| +) { | ||
| + h, err = readHeader(data) | ||
| + if err != nil { | ||
| + return nil, nil, nil, nil, nil, nil, nil, err | ||
| + } | ||
| + | ||
| + tocs, err = readTocs(data, h.Toc) | ||
| + if err != nil { | ||
| + return nil, nil, nil, nil, nil, nil, nil, err | ||
| + } | ||
| + | ||
| + var wg sync.WaitGroup | ||
| + wg.Add(len(tocs)) | ||
| + | ||
| + for _, toc := range tocs { | ||
| + switch toc.Type { | ||
| + case TocInstances: | ||
| + go func(offset uint64, count int32) { | ||
| + instances, err = readInstances(data, offset, count) | ||
| + wg.Done() | ||
| + }(toc.Offset, toc.Count) | ||
| + case TocIndoms: | ||
| + go func(offset uint64, count int32) { | ||
| + indoms, err = readInstanceDomains(data, offset, count) | ||
| + wg.Done() | ||
| + }(toc.Offset, toc.Count) | ||
| + case TocMetrics: | ||
| + go func(offset uint64, count int32) { | ||
| + metrics, err = readMetrics(data, offset, count) | ||
| + wg.Done() | ||
| + }(toc.Offset, toc.Count) | ||
| + case TocValues: | ||
| + go func(offset uint64, count int32) { | ||
| + values, err = readValues(data, offset, count) | ||
| + wg.Done() | ||
| + }(toc.Offset, toc.Count) | ||
| + case TocStrings: | ||
| + go func(offset uint64, count int32) { | ||
| + strings, err = readStrings(data, offset, count) | ||
| + wg.Done() | ||
| + }(toc.Offset, toc.Count) | ||
| + } | ||
| + } | ||
| + | ||
| + wg.Wait() | ||
| + | ||
| + if err != nil { | ||
| + return nil, nil, nil, nil, nil, nil, nil, err | ||
| + } | ||
| + | ||
| + return | ||
| +} | ||
| + | ||
| +// FixedVal will infer a fixed size value from the passed data | ||
| +func FixedVal(data uint64, t Type) (interface{}, error) { | ||
| + switch t { | ||
| + case Int32Type: | ||
| + return int32(data), nil | ||
| + case Uint32Type: | ||
| + return uint32(data), nil | ||
| + case Int64Type: | ||
| + return int64(data), nil | ||
| + case Uint64Type: | ||
| + return data, nil | ||
| + case FloatType: | ||
| + return math.Float32frombits(uint32(data)), nil | ||
| + case DoubleType: | ||
| + return math.Float64frombits(data), nil | ||
| + } | ||
| + | ||
| + return nil, errors.New("invalid type") | ||
| +} |
| @@ -0,0 +1,68 @@ | ||
| +package mmvdump | ||
| + | ||
| +import ( | ||
| + "os" | ||
| + "testing" | ||
| +) | ||
| + | ||
| +func data(filename string) []byte { | ||
| + f, err := os.Open(filename) | ||
| + if err != nil { | ||
| + panic(err) | ||
| + } | ||
| + | ||
| + s, err := os.Stat(filename) | ||
| + if err != nil { | ||
| + panic(err) | ||
| + } | ||
| + | ||
| + data := make([]byte, s.Size()) | ||
| + n, err := f.Read(data) | ||
| + if err != nil { | ||
| + panic(err) | ||
| + } | ||
| + | ||
| + if int64(n) != s.Size() { | ||
| + panic("Could not read complete file" + filename + " into memory") | ||
| + } | ||
| + | ||
| + return data | ||
| +} | ||
| + | ||
| +func TestMmvDump1(t *testing.T) { | ||
| + d := data("testdata/test1.mmv") | ||
| + | ||
| + h, tocs, metrics, values, instances, indoms, strings, err := Dump(d) | ||
| + if err != nil { | ||
| + t.Error(err) | ||
| + return | ||
| + } | ||
| + | ||
| + if h.G1 != h.G2 { | ||
| + t.Error("Invalid Header") | ||
| + } | ||
| + | ||
| + if len(tocs) != 3 { | ||
| + t.Errorf("expected number of tocs %d, got %d", 3, len(tocs)) | ||
| + } | ||
| + | ||
| + if len(indoms) != 0 { | ||
| + t.Errorf("expected number of indoms %d, got %d", 0, len(indoms)) | ||
| + } | ||
| + | ||
| + if len(strings) != 2 { | ||
| + t.Errorf("expected number of strings %d, got %d", 2, len(strings)) | ||
| + } | ||
| + | ||
| + if len(metrics) != 1 { | ||
| + t.Errorf("expected number of metrics %d, got %d", 1, len(metrics)) | ||
| + } | ||
| + | ||
| + if len(values) != 1 { | ||
| + t.Errorf("expected number of values %d, got %d", 1, len(values)) | ||
| + } | ||
| + | ||
| + if len(instances) != 0 { | ||
| + t.Errorf("expected number of instances %d, got %d", 0, len(instances)) | ||
| + } | ||
| +} |
| @@ -0,0 +1,161 @@ | ||
| +package mmvdump | ||
| + | ||
| +// MMVVersion is the current mmv format version | ||
| +const MMVVersion = 1 | ||
| + | ||
| +const ( | ||
| + // NameMax is the maximum allowed length of a name | ||
| + NameMax = 64 | ||
| + | ||
| + // StringMax is the maximum allowed length of a string | ||
| + StringMax = 256 | ||
| + | ||
| + // NoIndom is a constant used to indicate abscence of an indom from a metric | ||
| + NoIndom = -1 | ||
| +) | ||
| + | ||
| +// Header describes the data in a MMV header | ||
| +type Header struct { | ||
| + Magic [4]byte | ||
| + Version int32 | ||
| + G1, G2 uint64 | ||
| + Toc int32 | ||
| + Flag int32 | ||
| + Process, Cluster int32 | ||
| +} | ||
| + | ||
| +// TocType is an enumerated type with different types as values | ||
| +type TocType int32 | ||
| + | ||
| +// Values for TocType | ||
| +const ( | ||
| + TocIndoms TocType = iota + 1 | ||
| + TocInstances | ||
| + TocMetrics | ||
| + TocValues | ||
| + TocStrings | ||
| +) | ||
| + | ||
| +//go:generate stringer --type=TocType | ||
| + | ||
| +// Toc defines the contents in a valid TOC | ||
| +type Toc struct { | ||
| + Type TocType | ||
| + Count int32 | ||
| + Offset uint64 | ||
| +} | ||
| + | ||
| +// Instance defines the contents in a valid instance | ||
| +type Instance struct { | ||
| + Indom uint64 | ||
| + Padding uint32 | ||
| + Internal int32 | ||
| + External [NameMax]byte | ||
| +} | ||
| + | ||
| +// InstanceDomain defines the contents in a valid instance domain | ||
| +type InstanceDomain struct { | ||
| + Serial, Count uint32 | ||
| + Offset, Shorttext, Longtext uint64 | ||
| +} | ||
| + | ||
| +// Metric defines the contents in a valid Metric | ||
| +type Metric struct { | ||
| + Name [NameMax]byte | ||
| + Item uint32 | ||
| + Typ Type | ||
| + Sem Semantics | ||
| + Unit Unit | ||
| + Indom int32 | ||
| + Padding uint32 | ||
| + Shorttext, Longtext uint64 | ||
| +} | ||
| + | ||
| +// Value defines the contents in a PCP Value | ||
| +type Value struct { | ||
| + // uint64 is a holder type here, while printing it is expected that | ||
| + // the user will infer the value using the Val functions | ||
| + Val uint64 | ||
| + | ||
| + Extra int64 | ||
| + Metric uint64 | ||
| + Instance uint64 | ||
| +} | ||
| + | ||
| +// String wraps the payload for a PCP String | ||
| +type String struct { | ||
| + Payload [StringMax]byte | ||
| +} | ||
| + | ||
| +// Type is an enumerated type representing all valid types for a metric | ||
| +type Type int32 | ||
| + | ||
| +// Possible values for a Type | ||
| +const ( | ||
| + NoSupportType Type = iota - 1 | ||
| + Int32Type | ||
| + Uint32Type | ||
| + Int64Type | ||
| + Uint64Type | ||
| + FloatType | ||
| + DoubleType | ||
| + StringType | ||
| + UnknownType Type = 255 | ||
| +) | ||
| + | ||
| +//go:generate stringer --type=Type | ||
| + | ||
| +// Unit is an enumerated type with all possible units as values | ||
| +type Unit uint32 | ||
| + | ||
| +// Values for Space Units | ||
| +const ( | ||
| + ByteUnit Unit = 1<<28 | iota<<16 | ||
| + KilobyteUnit | ||
| + MegabyteUnit | ||
| + GigabyteUnit | ||
| + TerabyteUnit | ||
| + PetabyteUnit | ||
| + ExabyteUnit | ||
| +) | ||
| + | ||
| +// Values for Time Units | ||
| +const ( | ||
| + NanosecondUnit Unit = 1<<24 | iota<<12 | ||
| + MicrosecondUnit | ||
| + MillisecondUnit | ||
| + SecondUnit | ||
| + MinuteUnit | ||
| + HourUnit | ||
| +) | ||
| + | ||
| +// Values for Count Units | ||
| +const ( | ||
| + OneUnit Unit = 1<<20 | iota<<8 | ||
| +) | ||
| + | ||
| +//go:generate stringer --type=Unit | ||
| + | ||
| +// Semantics represents an enumerated type representing all possible semantics of a metric | ||
| +type Semantics int32 | ||
| + | ||
| +// Values for Semantics | ||
| +const ( | ||
| + NoSemantics Semantics = 0 | ||
| + CounterSemantics Semantics = 1 | ||
| + InstantSemantics Semantics = 3 | ||
| + DiscreteSemantics Semantics = 4 | ||
| +) | ||
| + | ||
| +//go:generate stringer -type=Semantics | ||
| + | ||
| +// Byte Lengths for Different Components | ||
| +const ( | ||
| + HeaderLength uint64 = 40 | ||
| + TocLength = 16 | ||
| + MetricLength = 104 | ||
| + ValueLength = 32 | ||
| + InstanceLength = 80 | ||
| + InstanceDomainLength = 32 | ||
| + StringLength = 256 | ||
| +) |