Expanded upon the control panel debug page and improved the UI a bit.

Trying to de-dupe the phrase strings to avoid allocating as much memory and creating as many pointers.
Shortened topic.status_closed_aria slightly.
Moved some things that should have been in various panel.css' into those panel.css'
Fixed the MemUsed dashboard item on Cosora.

Added the bunit template function.
This commit is contained in:
Azareal 2019-05-13 19:17:44 +10:00
parent 30722e1013
commit 9cd3cbadab
13 changed files with 213 additions and 108 deletions

View File

@ -282,25 +282,25 @@ type ResetPage struct {
/* WIP for dyntmpl */
type Panel struct {
*BasePanelPage
HTMLID string
HTMLID string
ClassNames string
TmplName string
Inner nobreak
TmplName string
Inner nobreak
}
type PanelAnalytics struct {
*BasePanelPage
FormAction string
TmplName string
Inner nobreak
TmplName string
Inner nobreak
}
type PanelAnalyticsStd struct{
type PanelAnalyticsStd struct {
Graph PanelTimeGraph
ViewItems []PanelAnalyticsItem
TimeRange string
Unit string
TimeType string
}
type PanelAnalyticsStdUnit struct{
type PanelAnalyticsStdUnit struct {
Graph PanelTimeGraph
ViewItems []PanelAnalyticsItemUnit
TimeRange string
@ -334,7 +334,7 @@ type PanelPage struct {
type GridElement struct {
ID string
Href string
Href string
Body string
Order int // For future use
Class string
@ -387,7 +387,7 @@ type PanelAnalyticsItem struct {
type PanelAnalyticsItemUnit struct {
Time int64
Count int64
Unit string
Unit string
}
type PanelAnalyticsPage struct {
@ -591,6 +591,10 @@ type PanelDebugPage struct {
Goroutines int
CPUs int
MemStats runtime.MemStats
TCache int
UCache int
TopicListThaw bool
}
type PageSimple struct {

View File

@ -99,6 +99,23 @@ func InitPhrases(lang string) error {
// [prefix][name]phrase
langPack.TmplPhrasesPrefixes = make(map[string]map[string]string)
var conMap = make(map[string]string) // Cache phrase strings so we can de-dupe items to reduce memory use. There appear to be some minor improvements with this, although we would need a more thorough check to be sure.
for name, phrase := range langPack.TmplPhrases {
_, ok := conMap[phrase]
if !ok {
conMap[phrase] = phrase
}
cItem := conMap[phrase]
prefix := strings.Split(name, ".")[0]
_, ok = langPack.TmplPhrasesPrefixes[prefix]
if !ok {
langPack.TmplPhrasesPrefixes[prefix] = make(map[string]string)
}
langPack.TmplPhrasesPrefixes[prefix][name] = cItem
}
// [prefix][name]phrase
/*langPack.TmplPhrasesPrefixes = make(map[string]map[string]string)
for name, phrase := range langPack.TmplPhrases {
prefix := strings.Split(name, ".")[0]
_, ok := langPack.TmplPhrasesPrefixes[prefix]
@ -106,7 +123,7 @@ func InitPhrases(lang string) error {
langPack.TmplPhrasesPrefixes[prefix] = make(map[string]string)
}
langPack.TmplPhrasesPrefixes[prefix][name] = phrase
}
}*/
langPack.TmplIndicesToPhrases = make([][][]byte, len(langTmplIndicesToNames))
for tmplID, phraseNames := range langTmplIndicesToNames {

View File

@ -1,6 +1,7 @@
package common
import (
"fmt"
"html/template"
"io"
"log"
@ -301,7 +302,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
tmpls.AddStd("account", "common.Account", accountPage)
basePage := &BasePanelPage{header, PanelStats{}, "dashboard", ReportForumID}
tmpls.AddStd("panel", "common.Panel", Panel{basePage, "panel_dashboard_right","","panel_dashboard", inter})
tmpls.AddStd("panel", "common.Panel", Panel{basePage, "panel_dashboard_right", "", "panel_dashboard", inter})
//tmpls.AddStd("panel_analytics", "common.PanelAnalytics", Panel{basePage, "panel_dashboard_right","panel_dashboard", inter})
var writeTemplate = func(name string, content interface{}) {
@ -688,6 +689,22 @@ func initDefaultTmplFuncMap() {
return template.HTML(phrases.GetLevelPhrase(level))
}
fmap["bunit"] = func(byteInt interface{}) interface{} {
var byteFloat float64
var unit string
switch bytes := byteInt.(type) {
case int:
byteFloat, unit = ConvertByteUnit(float64(bytes))
case int64:
byteFloat, unit = ConvertByteUnit(float64(bytes))
case uint64:
byteFloat, unit = ConvertByteUnit(float64(bytes))
default:
panic("bytes is not an int, int64 or uint64")
}
return fmt.Sprintf("%.1f", byteFloat) + unit
}
fmap["abstime"] = func(timeInt interface{}) interface{} {
time, ok := timeInt.(time.Time)
if !ok {

View File

@ -74,7 +74,7 @@ type CTemplateSet struct {
logger *log.Logger
loggerf *os.File
lang string
lang string
}
func NewCTemplateSet(in string) *CTemplateSet {
@ -108,6 +108,7 @@ func NewCTemplateSet(in string) *CTemplateSet {
"lang": true,
//"langf":true,
"level": true,
"bunit": true,
"abstime": true,
"reltime": true,
"scope": true,
@ -117,7 +118,7 @@ func NewCTemplateSet(in string) *CTemplateSet {
},
logger: log.New(f, "", log.LstdFlags),
loggerf: f,
lang:in,
lang: in,
}
}
@ -443,13 +444,13 @@ func (c *CTemplateSet) compile(name string, content string, expects string, expe
}
if c.lang == "normal" {
fout += "// nolint\nfunc Template_" + fname + "(tmpl_" + fname + "_i interface{}, w io.Writer) error {\n"
fout += `tmpl_` + fname + `_vars, ok := tmpl_` + fname + `_i.(` + expects + `)
fout += "// nolint\nfunc Template_" + fname + "(tmpl_" + fname + "_i interface{}, w io.Writer) error {\n"
fout += `tmpl_` + fname + `_vars, ok := tmpl_` + fname + `_i.(` + expects + `)
if !ok {
return errors.New("invalid page struct value")
}
`
fout += `var iw http.ResponseWriter
fout += `var iw http.ResponseWriter
gzw, ok := w.(common.GzipResponseWriter)
if ok {
iw = gzw.ResponseWriter
@ -1116,6 +1117,17 @@ ArgLoop:
litString("phrases.GetLevelPhrase("+leftParam+")", false)
c.importMap[langPkg] = langPkg
break ArgLoop
case "bunit":
// TODO: Implement bunit literals
leftOperand := node.Args[pos+1].String()
if len(leftOperand) == 0 {
panic("The leftoperand for function buint cannot be left blank")
}
leftParam, _ := c.compileIfVarSub(con, leftOperand)
out = "{\nbyteFloat, unit := common.ConvertByteUnit(float64(" + leftParam + "))\n"
out += "w.Write(fmt.Sprintf(\"%.1f\", byteFloat) + unit)\n"
literal = true
break ArgLoop
case "abstime":
// TODO: Implement level literals
leftOperand := node.Args[pos+1].String()
@ -1407,7 +1419,7 @@ func (c *CTemplateSet) retCall(name string, params ...interface{}) {
c.detail("returned from " + name + " => (" + pstr + ")")
}
func buildUserExprs(holder string) ([]string,[]string) {
func buildUserExprs(holder string) ([]string, []string) {
var userExprs = []string{
holder + ".CurrentUser.Loggedin",
holder + ".CurrentUser.IsSuperMod",

View File

@ -125,37 +125,37 @@ func (mts *MemoryTopicCache) Remove(id int) error {
}
// RemoveUnsafe is the unsafe version of Remove. THIS METHOD IS NOT THREAD-SAFE.
func (mts *MemoryTopicCache) RemoveUnsafe(id int) error {
_, ok := mts.items[id]
func (s *MemoryTopicCache) RemoveUnsafe(id int) error {
_, ok := s.items[id]
if !ok {
return ErrNoRows
}
delete(mts.items, id)
atomic.AddInt64(&mts.length, -1)
delete(s.items, id)
atomic.AddInt64(&s.length, -1)
return nil
}
// Flush removes all the topics from the cache, useful for tests.
func (mts *MemoryTopicCache) Flush() {
mts.Lock()
mts.items = make(map[int]*Topic)
mts.length = 0
mts.Unlock()
func (s *MemoryTopicCache) Flush() {
s.Lock()
s.items = make(map[int]*Topic)
s.length = 0
s.Unlock()
}
// ! Is this concurrent?
// Length returns the number of topics in the memory cache
func (mts *MemoryTopicCache) Length() int {
return int(mts.length)
func (s *MemoryTopicCache) Length() int {
return int(s.length)
}
// SetCapacity sets the maximum number of topics which this cache can hold
func (mts *MemoryTopicCache) SetCapacity(capacity int) {
func (s *MemoryTopicCache) SetCapacity(capacity int) {
// Ints are moved in a single instruction, so this should be thread-safe
mts.capacity = capacity
s.capacity = capacity
}
// GetCapacity returns the maximum number of topics this cache can hold
func (mts *MemoryTopicCache) GetCapacity() int {
return mts.capacity
func (s *MemoryTopicCache) GetCapacity() int {
return s.capacity
}

View File

@ -589,7 +589,7 @@
"forums_no_forums":"You don't have access to any forums.",
"topic.opening_post_aria":"The opening post for this topic",
"topic.status_closed_aria":"This topic has been locked",
"topic.status_closed_aria":"This topic is locked",
"topic.title_input_aria":"Topic Title Input",
"topic.update_button":"Update",
"topic.userinfo_aria":"The information on the poster",

View File

@ -41,6 +41,17 @@ func Debug(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
pi := c.PanelDebugPage{basePage, goVersion, dbVersion, uptime, openConnCount, qgen.Builder.GetAdapter().GetName(), goroutines, cpus, memStats}
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"panel_dashboard_right","","panel_debug", pi})
var tlen, ulen int
tcache := c.Topics.GetCache()
if tcache != nil {
tlen = tcache.Length()
}
ucache := c.Users.GetCache()
if ucache != nil {
ulen = ucache.Length()
}
topicListThawed := c.TopicListThaw.Thawed()
pi := c.PanelDebugPage{basePage, goVersion, dbVersion, uptime, openConnCount, qgen.Builder.GetAdapter().GetName(), goroutines, cpus, memStats, tlen, ulen, topicListThawed}
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_dashboard_right", "debug_page", "panel_debug", pi})
}

View File

@ -20,27 +20,73 @@
<div class="grid_item grid_stat"><span>{{.DBAdapter}}</span></div>
<div class="grid_item grid_stat"><span>?</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>{{lang "panel_debug_goroutine_count_label"}}</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>{{lang "panel_debug_cpu_count_label"}}</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>HeapAlloc</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>???</span></div>
<div class="grid_item grid_stat"><span>{{.Goroutines}}</span></div>
<div class="grid_item grid_stat"><span>{{.CPUs}}</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.HeapAlloc}}</span></div>
<div class="grid_item grid_stat"><span>?</span></div>
</div>
<div class="colstack_item colstack_head colstack_sub_head">
<div class="rowitem"><h2>Memory Statistics</h2></div>
</div>
<div id="panel_debug" class="colstack_grid">
<div class="grid_item grid_stat grid_stat_head"><span>Sys</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>HeapSys</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>HeapAlloc</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.Sys}} ({{bunit .MemStats.Sys}})</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.HeapSys}} ({{bunit .MemStats.HeapSys}})</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.HeapAlloc}} ({{bunit .MemStats.HeapAlloc}})</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>HeapIdle</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>HeapObjects</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.HeapSys}}</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.HeapIdle}}</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.HeapObjects}}</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>???</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>???</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>StackInuse</span></div>
<div class="grid_item grid_stat"><span>?</span></div>
<div class="grid_item grid_stat"><span>?</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.StackInuse}}</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.HeapIdle}} ({{bunit .MemStats.HeapIdle}})</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.HeapObjects}}</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.StackInuse}} ({{bunit .MemStats.StackInuse}})</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>MSpanInuse</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>MCacheInuse</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>MSpanSys</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.MSpanInuse}} ({{bunit .MemStats.MSpanInuse}})</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.MCacheInuse}} ({{bunit .MemStats.MCacheInuse}})</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.MSpanSys}} ({{bunit .MemStats.MSpanSys}})</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>MCacheSys</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>GCSys</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>OtherSys</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.MCacheSys}} ({{bunit .MemStats.MCacheSys}})</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.GCSys}} ({{bunit .MemStats.GCSys}})</span></div>
<div class="grid_item grid_stat"><span>{{.MemStats.OtherSys}} ({{bunit .MemStats.OtherSys}})</span></div>
</div>
<div class="colstack_item colstack_head colstack_sub_head">
<div class="rowitem"><h2>Caches</h2></div>
</div>
<div id="panel_debug" class="colstack_grid">
<div class="grid_item grid_stat grid_stat_head"><span>Topic Cache</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>User Cache</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>Reply Cache</span></div>
<div class="grid_item grid_stat"><span>{{.TCache}}</span></div>
<div class="grid_item grid_stat"><span>{{.UCache}}</span></div>
<div class="grid_item grid_stat"><span>0</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>Topic List</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>???</span></div>
<div class="grid_item grid_stat grid_stat_head"><span>???</span></div>
<div class="grid_item grid_stat"><span>{{if .TopicListThaw}}Thawed{{else}}Sleeping{{end}}</span></div>
<div class="grid_item grid_stat"><span>?</span></div>
<div class="grid_item grid_stat"><span>?</span></div>
</div>

View File

@ -1594,42 +1594,13 @@ red {
padding-bottom: 0px;
padding-right: 10px;
}
.grid_item span {
.grid_item span, .grid_item a {
margin-top: 16px;
margin-bottom: 16px;
margin-left: auto;
margin-right: auto;
text-align: center;
}
/* TODO: Move these to panel.css */
#dash-version:before, #dash-cpu:before, #dash-ram:before, #dash-totonline:before, #dash-gonline:before, #dash-uonline:before, #dash-reqs:before, #dash-postsperday:before, #dash-topicsperday:before {
display: inline-block;
background: var(--tinted-background-color);
font: normal normal normal 14px/1 FontAwesome;
font-size: 20px;
padding-left: 17px;
padding-top: 16px;
padding-right: 19px;
color: hsl(0,0%,20%);
}
#dash-version:before {
content: "\f126";
}
#dash-cpu:before {
content: "\f2db";
}
#dash-ram:before {
content: "\f233";
}
#dash-totonline:before, #dash-gonline:before, #dash-uonline:before {
content: "\f007";
}
#dash-reqs:before {
content: "\f080";
}
#dash-postsperday:before, #dash-topicsperday:before {
content: "\f27b";
}
@media(min-width: 1000px) {
.footer {
@ -1648,13 +1619,6 @@ red {
max-width: 1000px;
margin-left: auto;
margin-right: auto;
}
.footer {
max-width: 1000px;
margin-left: auto;
margin-right: auto;
}
#main {
padding-top: 18px;
padding-left: 16px;
padding-right: 16px;
@ -1662,6 +1626,9 @@ red {
border-right: 1px solid hsl(20,0%,95%);
}
.footer {
max-width: 1000px;
margin-left: auto;
margin-right: auto;
padding-left: 8px;
padding-right: 8px;
}
@ -1686,10 +1653,7 @@ red {
.like_count {
margin-right: 1px;
}
.like_count:after {
margin-right: 6px;
}
.created_at:before, .ip_item:before {
.like_count:after, .created_at:before, .ip_item:before {
margin-right: 6px;
}
}

View File

@ -80,6 +80,41 @@
font-size: 17px;
color: hsl(0,0%,40%);
}
/* TODO: Move these to panel.css */
#dash-version:before, #dash-cpu:before, #dash-ram:before, #dash-memused:before, #dash-totonline:before, #dash-gonline:before, #dash-uonline:before, #dash-reqs:before, #dash-postsperday:before, #dash-topicsperday:before {
display: inline-block;
background: var(--tinted-background-color);
font: normal normal normal 14px/1 FontAwesome;
font-size: 20px;
padding-left: 17px;
padding-top: 16px;
padding-right: 19px;
color: hsl(0,0%,20%);
}
#dash-version:before {
content: "\f126";
}
#dash-cpu:before, #dash-memused:before {
content: "\f2db";
}
#dash-ram:before {
content: "\f233";
}
#dash-totonline:before, #dash-gonline:before, #dash-uonline:before {
content: "\f007";
}
#dash-reqs:before {
content: "\f080";
}
#dash-postsperday:before, #dash-topicsperday:before {
content: "\f27b";
}
#panel_debug .grid_stat:not(.grid_stat_head) {
margin-bottom: 8px;
}
.debug_page.colstack_right .colstack_sub_head {
margin-top: 6px;
}
.complex_rowlist {
background-color: inherit !important;

View File

@ -1399,9 +1399,9 @@ input[type=checkbox]:checked + label .sel {
}
}
@media(max-width: 850px) {
/**/
}
{{/**@media(max-width: 850px) {
//
}**/}}
@media(min-width: 1010px) {
#container {
@ -1412,11 +1412,10 @@ input[type=checkbox]:checked + label .sel {
margin-left: auto;
margin-right: auto;
}
.footBlock {
.footBlock, .footer {
display: flex;
}
.footer {
display: flex;
flex-direction: column;
}

View File

@ -1026,21 +1026,6 @@ blockquote:first-child {
background-color: var(--main-block-color);
}
#panel_dashboard_right .colstack_head .rowitem {
padding: 10px;
}
#panel_dashboard_right .colstack_head .rowitem h1 {
font-size: 15px;
margin-left: auto;
}
#panel_dashboard_right .colstack_head a {
text-align: center;
width: 100%;
display: block;
font-size: 15px;
}
@media(max-width: 935px) {
.simple .user_tag {
display: none;

View File

@ -43,6 +43,21 @@
content: "{{lang "panel_delete_button_text" . }}";
}
#panel_dashboard_right .colstack_head .rowitem {
padding: 10px;
}
#panel_dashboard_right .colstack_head .rowitem h1, #panel_dashboard_right .colstack_sub_head .rowitem h2 {
font-size: 15px;
margin-left: auto;
margin-right: auto;
}
#panel_dashboard_right .colstack_head a, #panel_dashboard_right .colstack_sub_head a {
text-align: center;
width: 100%;
display: block;
font-size: 15px;
}
#panel_forums .rowitem {
display: flex;
}