Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (

"github.com/sjmudd/ps-top/config"
"github.com/sjmudd/ps-top/model/tableio"
"github.com/sjmudd/ps-top/presenter/tableiolatency"
"github.com/sjmudd/ps-top/presenter/tableioops"
"github.com/sjmudd/ps-top/pstable"
"github.com/sjmudd/ps-top/view"
"github.com/sjmudd/ps-top/wrapper/tableiolatency"
"github.com/sjmudd/ps-top/wrapper/tableioops"
)

// DBCollector owns all the Tabler instances and coordinates data collection.
Expand Down
105 changes: 105 additions & 0 deletions presenter/base.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package presenter

import (
"fmt"
"time"

"github.com/sjmudd/ps-top/model"
)

// BasePresenter[T, M] implements Tabler for any model M that satisfies
// model.Model[T]. It delegates to a content function provided at construction.
type BasePresenter[T any, M model.Model[T]] struct {
model M
name string
sortFn func([]T) // optional sorting function; nil = no sort
hasData func(T) bool // predicate for counting rows with data; nil = count all rows
contentFn func(T, T) string // formats a single row
}

// NewBasePresenter creates a new BasePresenter with the given model and options.
func NewBasePresenter[T any, M model.Model[T]](
model M,
name string,
sortFn func([]T),
hasData func(T) bool,
contentFn func(T, T) string,
) *BasePresenter[T, M] {
return &BasePresenter[T, M]{
model: model,
name: name,
sortFn: sortFn,
hasData: hasData,
contentFn: contentFn,
}
}

// Collect implements Tabler.
func (bp *BasePresenter[T, M]) Collect() {
bp.model.Collect()
if bp.sortFn != nil {
results := bp.model.GetResults()
bp.sortFn(results)
}
}

// ResetStatistics implements Tabler.
func (bp *BasePresenter[T, M]) ResetStatistics() {
bp.model.ResetStatistics()
}

// HaveRelativeStats implements Tabler.
func (bp *BasePresenter[T, M]) HaveRelativeStats() bool {
return bp.model.HaveRelativeStats()
}

// FirstCollectTime implements Tabler.
func (bp *BasePresenter[T, M]) FirstCollectTime() time.Time {
return bp.model.GetFirstCollected()
}

// LastCollectTime implements Tabler.
func (bp *BasePresenter[T, M]) LastCollectTime() time.Time {
return bp.model.GetLastCollected()
}

// WantRelativeStats implements Tabler.
func (bp *BasePresenter[T, M]) WantRelativeStats() bool {
return bp.model.WantRelativeStats()
}

// RowContent implements Tabler.
func (bp *BasePresenter[T, M]) RowContent() []string {
results := bp.model.GetResults()
n := len(results)
return RowsFromGetter(n, func(i int) string {
return bp.contentFn(results[i], bp.model.GetTotals())
})
}

// TotalRowContent implements Tabler.
func (bp *BasePresenter[T, M]) TotalRowContent() string {
totals := bp.model.GetTotals()
return TotalRowContent(totals, bp.contentFn)
}

// EmptyRowContent implements Tabler.
func (bp *BasePresenter[T, M]) EmptyRowContent() string {
return EmptyRowContent(bp.contentFn)
}

// Description implements Tabler.
func (bp *BasePresenter[T, M]) Description() string {
results := bp.model.GetResults()
n := len(results)
count := n
if bp.hasData != nil {
count = CountIf(n, func(i int) bool { return bp.hasData(results[i]) })
}
return fmt.Sprintf("%s %d rows", bp.name, count)
}

// GetModel returns the embedded model. Used by special presenters like tableioops.
func (bp *BasePresenter[T, M]) GetModel() M {
return bp.model
}
12 changes: 6 additions & 6 deletions wrapper/common.go → presenter/common.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package wrapper
package presenter

import (
"fmt"
Expand All @@ -7,7 +7,7 @@ import (
)

// RowsFromGetter builds a slice of strings by calling the provided getter
// for each index. This centralizes the common loop used by many wrapper
// for each index. This centralizes the common loop used by many presenter
// packages to produce display rows.
func RowsFromGetter(n int, get func(i int) string) []string {
rows := make([]string, 0, n)
Expand All @@ -18,7 +18,7 @@ func RowsFromGetter(n int, get func(i int) string) []string {
}

// CountIf counts how many indices in [0,n) satisfy the predicate.
// Used by wrappers to implement Description() which counts rows with data.
// Used by presenters to implement Description() which counts rows with data.
func CountIf(n int, pred func(i int) bool) int {
count := 0
for i := 0; i < n; i++ {
Expand All @@ -31,7 +31,7 @@ func CountIf(n int, pred func(i int) bool) int {

// TotalRowContent returns the formatted totals row by calling the provided
// content function with the totals value for both row and totals.
// This removes the repeated pattern found in many wrapper packages.
// This removes the repeated pattern found in many presenter packages.
func TotalRowContent[T any](totals T, content func(T, T) string) string {
return content(totals, totals)
}
Expand All @@ -44,7 +44,7 @@ func EmptyRowContent[T any](content func(T, T) string) string {
return content(empty, empty)
}

// MakeTableIOHeadings constructs a heading string used by the tableio wrappers.
// MakeTableIOHeadings constructs a heading string used by the tableio presenters.
// The `kind` parameter should be either "Latency" or "Ops" (or similar) and will
// be interpolated into the common table IO heading format.
func MakeTableIOHeadings(kind string) string {
Expand All @@ -70,7 +70,7 @@ func TimePct(sum, totals uint64) (string, string) {
// PctStrings returns a slice of formatted percentage strings for each value
// relative to the provided total. This centralizes the common pattern of
// calling utils.FormatPct(utils.Divide(value, total)). It helps reduce
// duplicated code across wrapper content formatters.
// duplicated code across presenter content formatters.
func PctStrings(total uint64, values ...uint64) []string {
out := make([]string, len(values))
for i, v := range values {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (

"github.com/sjmudd/ps-top/config"
"github.com/sjmudd/ps-top/model/fileinfo"
"github.com/sjmudd/ps-top/presenter"
"github.com/sjmudd/ps-top/utils"
"github.com/sjmudd/ps-top/wrapper"
)

var (
Expand All @@ -33,9 +33,9 @@ var (
name = ""
}

timeStr, pctStr := wrapper.TimePct(row.SumTimerWait, totals.SumTimerWait)
pct := wrapper.PctStrings(row.SumTimerWait, row.SumTimerRead, row.SumTimerWrite, row.SumTimerMisc)
opsPct := wrapper.PctStrings(row.CountStar, row.CountRead, row.CountWrite, row.CountMisc)
timeStr, pctStr := presenter.TimePct(row.SumTimerWait, totals.SumTimerWait)
pct := presenter.PctStrings(row.SumTimerWait, row.SumTimerRead, row.SumTimerWrite, row.SumTimerMisc)
opsPct := presenter.PctStrings(row.CountStar, row.CountRead, row.CountWrite, row.CountMisc)

return fmt.Sprintf("%10s %6s|%6s %6s %6s|%8s %8s|%8s %6s %6s %6s|%s",
timeStr,
Expand All @@ -53,26 +53,26 @@ var (
}
)

// Wrapper wraps a FileIoLatency struct.
type Wrapper struct {
*wrapper.BaseWrapper[fileinfo.Row, *fileinfo.FileIoLatency]
// Presenter presents a FileIoLatency struct.
type Presenter struct {
*presenter.BasePresenter[fileinfo.Row, *fileinfo.FileIoLatency]
}

// NewFileSummaryByInstance creates a wrapper around FileIoLatency.
func NewFileSummaryByInstance(cfg *config.Config, db *sql.DB) *Wrapper {
// NewFileSummaryByInstance creates a presenter for FileIoLatency.
func NewFileSummaryByInstance(cfg *config.Config, db *sql.DB) *Presenter {
fiol := fileinfo.NewFileSummaryByInstance(cfg, db)
bw := wrapper.NewBaseWrapper(
bp := presenter.NewBasePresenter(
fiol,
"File I/O Latency (file_summary_by_instance)",
defaultSort,
defaultHasData,
defaultContent,
)
return &Wrapper{BaseWrapper: bw}
return &Presenter{BasePresenter: bp}
}

// Headings returns the headings for a table.
func (w *Wrapper) Headings() string {
func (p *Presenter) Headings() string {
return fmt.Sprintf("%10s %6s|%6s %6s %6s|%8s %8s|%8s %6s %6s %6s|%s",
"Latency",
"%",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ import (

"github.com/sjmudd/ps-top/config"
"github.com/sjmudd/ps-top/model/memoryusage"
"github.com/sjmudd/ps-top/presenter"
"github.com/sjmudd/ps-top/utils"
"github.com/sjmudd/ps-top/wrapper"
)

// Wrapper wraps a MemoryUsage struct and implements the Tabler interface
// via embedded BaseWrapper.
type Wrapper struct {
*wrapper.BaseWrapper[memoryusage.Row, *memoryusage.MemoryUsage]
// Presenter presents a MemoryUsage struct and implements the Tabler interface
// via embedded BasePresenter.
type Presenter struct {
*presenter.BasePresenter[memoryusage.Row, *memoryusage.MemoryUsage]
}

// NewMemoryUsage creates a wrapper around MemoryUsage.
func NewMemoryUsage(cfg *config.Config, db *sql.DB) *Wrapper {
// NewMemoryUsage creates a presenter for MemoryUsage.
func NewMemoryUsage(cfg *config.Config, db *sql.DB) *Presenter {
mu := memoryusage.NewMemoryUsage(cfg, db)

// Sort by CurrentBytesUsed descending, then Name ascending.
Expand Down Expand Up @@ -64,17 +64,17 @@ func NewMemoryUsage(cfg *config.Config, db *sql.DB) *Wrapper {
name)
}

bw := wrapper.NewBaseWrapper(mu,
bp := presenter.NewBasePresenter(mu,
"Memory Usage (memory_summary_global_by_event_name)",
sortFn,
hasData,
contentFn,
)
return &Wrapper{BaseWrapper: bw}
return &Presenter{BasePresenter: bp}
}

// Headings returns the headings for a table.
func (w *Wrapper) Headings() string {
func (p *Presenter) Headings() string {
return "CurBytes % High Bytes|MemOps %|CurAlloc % HiAlloc|Memory Area"
// 1234567890 100.0% 1234567890|123456789 100.0%|12345678 100.0% 12345678|Some memory name
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (

"github.com/sjmudd/ps-top/config"
"github.com/sjmudd/ps-top/model/mutexlatency"
"github.com/sjmudd/ps-top/presenter"
"github.com/sjmudd/ps-top/utils"
"github.com/sjmudd/ps-top/wrapper"
)

var (
Expand Down Expand Up @@ -37,25 +37,25 @@ var (
}
)

// Wrapper wraps a MutexLatency struct.
type Wrapper struct {
*wrapper.BaseWrapper[mutexlatency.Row, *mutexlatency.MutexLatency]
// Presenter presents a MutexLatency struct.
type Presenter struct {
*presenter.BasePresenter[mutexlatency.Row, *mutexlatency.MutexLatency]
}

// NewMutexLatency creates a wrapper around mutexlatency.
func NewMutexLatency(cfg *config.Config, db *sql.DB) *Wrapper {
// NewMutexLatency creates a presenter for mutexlatency.
func NewMutexLatency(cfg *config.Config, db *sql.DB) *Presenter {
ml := mutexlatency.NewMutexLatency(cfg, db)
bw := wrapper.NewBaseWrapper(
bp := presenter.NewBasePresenter(
ml,
"Mutex Latency (events_waits_summary_global_by_event_name)",
defaultSort,
defaultHasData,
defaultContent,
)
return &Wrapper{BaseWrapper: bw}
return &Presenter{BasePresenter: bp}
}

// Headings returns the headings for a table.
func (w *Wrapper) Headings() string {
func (p *Presenter) Headings() string {
return fmt.Sprintf("%10s %8s %8s|%s", "Latency", "MtxCnt", "%", "Mutex Name")
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (

"github.com/sjmudd/ps-top/config"
"github.com/sjmudd/ps-top/model/stageslatency"
"github.com/sjmudd/ps-top/presenter"
"github.com/sjmudd/ps-top/utils"
"github.com/sjmudd/ps-top/wrapper"
)

var (
Expand Down Expand Up @@ -37,25 +37,25 @@ var (
}
)

// Wrapper wraps a Stages struct.
type Wrapper struct {
*wrapper.BaseWrapper[stageslatency.Row, *stageslatency.StagesLatency]
// Presenter presents a StagesLatency struct.
type Presenter struct {
*presenter.BasePresenter[stageslatency.Row, *stageslatency.StagesLatency]
}

// NewStagesLatency creates a wrapper around stageslatency.
func NewStagesLatency(cfg *config.Config, db *sql.DB) *Wrapper {
// NewStagesLatency creates a presenter for stageslatency.
func NewStagesLatency(cfg *config.Config, db *sql.DB) *Presenter {
sl := stageslatency.NewStagesLatency(cfg, db)
bw := wrapper.NewBaseWrapper(
bp := presenter.NewBasePresenter(
sl,
"SQL Stage Latency (events_stages_summary_global_by_event_name)",
defaultSort,
defaultHasData,
defaultContent,
)
return &Wrapper{BaseWrapper: bw}
return &Presenter{BasePresenter: bp}
}

// Headings returns the headings for a table.
func (w *Wrapper) Headings() string {
func (p *Presenter) Headings() string {
return fmt.Sprintf("%10s %6s %8s|%s", "Latency", "%", "Counter", "Stage Name")
}
Loading
Loading