ID:1970745
 
(See the best response by Kaiochao.)
Code:
                                 Profile results (total time)
Proc Name Self CPU Total CPU Real Time Calls
------------------------------------------- --------- --------- --------- ---------
/obj/chatbox_input/proc/LoopInput 0.002 0.004 99.862 21
/obj/chatbox_input/New 0.000 0.004 99.862 21
/obj/chatbox_input_output/proc/Update 0.005 0.005 99.862 21
/mob/proc/J_AI 0.000 0.001 11.322 5
/mob/Player/verb/Werewolf 0.316 0.316 3.712 4
/client/verb/KeyDown 0.012 0.043 2.998 484
/mob/Player/key_down 0.000 0.014 2.969 102
/mob/Player/verb/StrengthTrain 0.000 0.000 2.955 3
/chatbox/proc/_update 0.002 0.030 1.580 60
/mob/Mods/verb/Summon_Player 0.000 0.000 1.276 1
/mob/Player/verb/Attack 0.013 0.319 0.319 31
/proc/F_damage 0.001 0.299 0.299 6
/icon/proc/RscFile 0.298 0.298 0.298 12
/maptext/New 0.013 0.094 0.095 445
/maptext/proc/update 0.044 0.081 0.082 445
/mob/Player/Stat 0.016 0.059 0.058 1534
/proc/ConvertTime 0.043 0.043 0.042 1534
/proc/Border 0.035 0.040 0.040 1848
/proc/_message 0.000 0.034 0.032 96
/obj/chatbox_input/key_down 0.003 0.017 0.017 376
/client/Move 0.008 0.016 0.016 12260
/client/verb/KeyUp 0.015 0.015 0.015 491
/mob/Player/verb/Interaction 0.001 0.014 0.014 31
/chatbox/proc/_enter 0.000 0.015 0.014 60
/chatbox/proc/_getlog 0.011 0.013 0.012 60
/client/MouseEntered 0.001 0.011 0.011 201
/mob/proc/Create_Name 0.007 0.010 0.010 17
/mob/Move 0.008 0.009 0.009 12402
/mob/proc/LoadC 0.003 0.008 0.008 1
0.006 0.006 0.006 2370
/mob/proc/Found 0.006 0.006 0.006 6
/mob/Read 0.005 0.005 0.005 1
/mob/Player/verb/OOC 0.000 0.005 0.005 4
/obj/chatbox_input/proc/CheckInput 0.002 0.003 0.003 5568
/obj/chatbox_input/proc/KillInput 0.001 0.001 0.002 20
/client/proc/chatlog_record 0.002 0.002 0.002 61
/chatbox_msgs/proc/Get 0.002 0.002 0.002 476
/proc/hp_update 0.000 0.001 0.001 10
/proc/updatebar 0.001 0.001 0.001 10
/mob/proc/IsMuted 0.001 0.001 0.001 20
/client/verb/KeyRepeat 0.001 0.001 0.001 29
/client/Click 0.001 0.001 0.001 14
/mob/Monster/proc/Attack 0.001 0.001 0.001 138
/mob/Monster/Bump 0.000 0.001 0.001 138
/mob/Monster/Move 0.000 0.001 0.001 142
/mob/proc/Flick_Hurt 0.000 0.000 0.000 6
/obj/chatbox_input_output/New 0.000 0.000 0.000 21
/mob/proc/ishome 0.000 0.000 0.000 1
0.000 0.000 0.000 21
/mob/proc/Setup_HUD 0.000 0.000 0.000 1
/obj/chatbox_input/proc/ProcessText 0.000 0.000 0.000 2
/mob/proc/BattleEffects 0.000 0.000 0.000 6
/obj/chatbox_input/proc/CheckAdminCommand 0.000 0.000 0.000 19
/obj/chatbox_input/proc/CheckValidInput 0.000 0.000 0.000 20
/mob/proc/J_getacc 0.000 0.000 0.000 23
/mob/proc/J_dienpc 0.000 0.000 0.000 1
/datum/proc/key_up 0.000 0.000 0.000 373
/datum/proc/key_repeat 0.000 0.000 0.000 29
/datum/proc/click 0.000 0.000 0.000 11
/proc/showbars 0.000 0.000 0.000 10
/proc/hidebars 0.000 0.000 0.000 6
/icon/proc/Blend 0.000 0.000 0.000 1
/proc/updatebar2 0.000 0.000 0.000 10
/mob/proc/Death 0.000 0.000 0.000 6
/proc/en_update 0.000 0.000 0.000 10
/client/proc/chatbox_remove 0.000 0.000 0.000 1
/mob/Player/verb/Admin 0.000 0.000 0.000 1
/proc/Target 0.000 0.000 0.000 1
/mob/proc/BaseDamage 0.000 0.000 0.000 6
/proc/F_validColor 0.000 0.000 0.000 6
/mob/Player/key_up 0.000 0.000 0.000 111
/mob/Player/proc/Stat_Update 0.006 0.101 0.000 1
/mob/Monster/proc/J_WB 0.000 0.000 0.000 1
/__f_damage_CacheEntry/New 0.000 0.000 0.000 1
/__f_damage_Cache/proc/get 0.000 0.000 0.000 6
/__f_damage_Cache/proc/put 0.000 0.000 0.000 1
/F_Damage_Horizontal_Alignment/center/align 0.000 0.000 0.000 12
/mob/proc/Count_Time 0.000 0.000 0.000 1
/client/Click 0.000 0.000 0.000 14
/mob/proc/LoseHP 0.000 0.000 0.000 6
/chatbox/proc/_got_updates 0.000 0.000 0.000 60
/chatbox/New 0.000 0.000 0.000 1
/chatbox/shadow/New 0.000 0.000 0.000 1
/chatbox_msg/New 0.000 0.000 0.000 36
/chatbox_msg/proc/_format 0.000 0.000 0.000 36
/chatbox_msg/proc/_parse 0.000 0.000 0.000 36
/chatbox_msgs/New 0.000 0.000 0.000 1
/chatbox_msgs/proc/Add 0.000 0.000 0.000 60
/mob/proc/Give_Reward 0.000 0.000 0.000 1
/chatbox_msgs/proc/pos 0.000 0.000 0.000 536
/sound/New 0.000 0.000 0.000 37
/icon/New 0.000 0.000 0.000 7
/mob/proc/BattleStanceOff 0.000 0.000 0.000 6
/mob/proc/BattleStance 0.000 0.000 0.000 31
/icon/proc/Width 0.000 0.000 0.000 6
/icon/proc/Height 0.000 0.000 0.000 6
/mob/proc/Check_level 0.000 0.000 0.000 3
/client/proc/chatbox_build 0.000 0.000 0.000 1


Problem description:
Server runs fine at first but after awhile it gets unbearably laggy.
Real Time is increased by sleep statements, so high values aren't usually a sign of actual CPU lag occurring.

It might be worth showing code if you want relevant optimization advice, though.
client
command_text = "chat-say \""


// chatbox settings

chatbox
screen_loc = "1:16,1:16"

maptext_height = 128
maptext_width = 250

maxlines = 50
chatlines = 9

font_family = "Verdana"
font_color = "#FFFFFF"

text_shadow = "#222d"

chatbox_gui
icon = 'chatbox_gui.dmi'

background
icon = 'chatbox_bg.dmi'
// screen_loc = "0:16,1:1 to 13:15,1"//2:28
mouse_opacity = 0

start
icon_state = "start"
screen_loc = "8:18,3:-15"

up
icon_state = "up"
screen_loc = "8:18,3:-30"

down
icon_state = "down"
screen_loc = "8:18,2:-15"

end
icon_state = "end"
screen_loc = "8:18,2:-30"

clear
icon_state = "clear"
screen_loc = "8:35,3:-15"


say
icon_state = "say"
screen_loc = "8:35,3:-30"
Click()
usr<<'Click.wav'
if(usr.CHAT == "Say")return
usr.CHAT = "Say"
usr.InfoShow("Your chat is set to view!")


worldchat
icon_state = "world"
screen_loc = "8:35,3:-45"
Click()
usr<<'Click.wav'
if(usr.CHAT == "World")return
usr.CHAT = "World"
usr.InfoShow("Your chat is set to global!")
_message(usr,"<font size = -1><b>System</b>: Your chat is set to global!","red")
..()

Click()
..()
chatbox
maxlines = 1000
//////////////////
obj
chatbox_input_output
var/message
var/obj/chatbox_input/master
mouse_opacity = 0
screen_loc = "1:16,1:150"
maptext_height = 128
maptext_width = 400
layer=FLY_LAYER+101

New(obj/o){
master = o
spawn(){Update()}
}

proc
Update(){
spawn while(src && master){
if(lentext(master.message) > 55){
maptext="<font face=Arial size=\"3\"><b>[copytext(master.message,lentext(master.message)-55,lentext(master.message))]</b></font>"
}
else{
maptext="<font face=Arial size=\"3\"><b>[master.message]</b></font>"
}
sleep(world.tick_lag)
}
}

chatbox_input
icon='chatbox_bg.dmi'
mouse_opacity = 0
screen_loc = "1:16,1:150 to 13:1,1"
maptext_height = 128
maptext_width = 350
layer=FLY_LAYER+101
var/message
// var/mob/Owner
var/shifting=0
var/obj/output
var/disallowed[] = list("delete","ctrl","alt","tab","escape","home","north","south","west","east","northeast","northwest","southeast","southwest","insert")

proc
LoopInput(){
while(src){
sleep(world.tick_lag)
CheckInput()
}
}

CheckInput(){
if(Owner.client.keys["shift"]){
shifting=1
}
else{
shifting=0
}
}

ProcessText(key){
if(shifting && key=="1"){return "!"}
else if(shifting && key=="2"){return "@"}
else if(shifting && key=="3"){return "#"}
else if(shifting && key=="4"){return "$"}
else if(shifting && key=="5"){return "%"}
else if(shifting && key=="6"){return "^"}
else if(shifting && key=="7"){return "&"}
else if(shifting && key=="8"){return "*"}
else if(shifting && key=="9"){return "("}
else if(shifting && key=="0"){return ")"}
else if(shifting && key=="-"){return "_"}
else if(shifting && key=="="){return "+"}
else if(shifting && key=="\["){return "{"}
else if(shifting && key=="\]"){return "}"}
else if(shifting && key=="\\"){return "|"}
else if(shifting && key==";"){return ":"}
else if(shifting && key=="'"){return "\""}
else if(shifting && key==","){return "<"}
else if(shifting && key=="."){return ">"}
else if(shifting && key=="/"){return "?"}
else return key
}

KillInput(){
Owner.client.focus = Owner
Owner.client.screen -= src
del(src)
}

CheckAdminCommand(mob/Player/Owner, msg){
if(Owner.isadmin && msg == "/reboot"){
world.Reboot()
return 1
}
else if(Owner.isadmin && findtext(msg, "/kick")){
msg = replacetext(msg, "/kick ", "")
Owner.Boot(msg)
return 1
}
else if(Owner.isadmin && findtext(msg, "/mute")){
// msg = replacetext(msg, "/kick ", "")
Owner.Mute()
return 1
}
else if(Owner.isadmin && findtext(msg, "/unmute")){
// msg = replacetext(msg, "/kick ", "")
Owner.UnMute()
return 1
}
else if(Owner.isadmin && findtext(msg, "/ban")){
// msg = replacetext(msg, "/kick ", "")
Owner.Ban()
return 1
}
else if(Owner.isadmin && findtext(msg, "/unban")){
// msg = replacetext(msg, "/kick ", "")
Owner.UnBan()
return 1
}
else if(Owner.isadmin && findtext(msg, "/summon")){
// msg = replacetext(msg, "/kick ", "")
Owner.Summon_Player()
return 1
}
else if(Owner.isadmin && findtext(msg, "/teleport")){
// msg = replacetext(msg, "/kick ", "")
Owner.Teleport()
return 1
}
else if(msg == "/who"){
Owner.Who()
var/players
var/cnt
for(var/mob/Player/m in world){
players += "[m.name], "
cnt++
}
players = copytext(players,1,lentext(players)-1)
_message(Owner, "Players online:", "#FFFFFF")
_message(Owner, players, "#FFFFFF")
if(cnt == 1){
_message(Owner, "[cnt] player online.", "#FFFFFF")
}
else{
_message(Owner, "[cnt] players online.", "#FFFFFF")
}
return 1
}
else{
return 0
}
}

CheckValidInput(){
if(lentext(message) < 1){
_message(Owner,"Your message is too short!", "#FFFFFF")
return 1
}
}

key_down(k){
if(k=="return"){
if(usr.IsMuted())
return
if(CheckValidInput()){KillInput()}
if(CheckAdminCommand(Owner,message)){KillInput();return}
if(Owner.CHAT == null)return
if(Owner.Omute == 1)
Owner.skalert("OOC is disabled!")
if(Owner.Mute == 1)
src << output("You're muted!", "output1")
if(Owner.CHAT == "Say")
_message(view(Owner.client.view,Owner), "(Say) [Owner.name]: [message]", "#00FFEE")
if(Owner.CHAT == "World")
if(Owner.key in admin)
_message(world,"<font color=yellow>(Admin)[Owner.name]:</font> [message]")
KillInput()
return
if(Owner.key in mods)
_message(world,"<font color=yellow>(Mod)[Owner.name]:</font> [message]")
KillInput()
return
else
_message(world,"<font color=yellow>(OOC)[Owner.name]:</font> [message]")
KillInput()
return
KillInput()
}
else{
if(lentext(message) < 60){
if(k in disallowed){return 0}
if(k=="space"){message+=" ";return}
if(k=="back"){message=copytext(message,1,lentext(message));return}
if(shifting){message+=uppertext(ProcessText(k))}else{if(k!="shift"){message+=k}}
}
else{
_message(Owner, "Your message is too long!", "#FFFFFF")
}
}
}

New(mob/M){
var/obj/o = new/obj/chatbox_input_output(src)
M.client.focus = src
Owner = M
M.client.screen += o
M.client.screen += src
spawn(){LoopInput()}
return ..()
}


I get this runtime error also.

runtime error: Cannot read null.client
proc name: New (/obj/chatbox_input/New)
source file: Chatbox2.dm,278
usr: null
src: the chatbox input (/obj/chatbox_input)
call stack:
the chatbox input (/obj/chatbox_input): New(null)
Nero (/mob/Player): Read(players/Edit Nero.sav (/savefile))
Nero (/mob/Player): LoadC()
Nero (/mob/Player): Login()
In response to Edit Nero
Best response
The runtime error is very straightforward. In chatbox_input.New() you're trying to access the client of a mob that has no client (yet).

Also,
* length() is better/faster/stronger than lentext(), so use it instead.
* copytext(master.message,lentext(master.message)-55,lentext(m aster.message)) can be simplified to copytext(master.message, -55) (you still have to check if length(master.message) > 55).
* You're overusing spawn. It shouldn't cause any extra lag, but it might be hiding information from the profiler. The solution is to put "set waitfor = FALSE" at the top of all of your procs with infinite timed loops (Update(), LoopInput()), and remove all spawns from this code.
It shouldn't cause any extra lag

Wrong. Every time you use a spawn, a scheduler reinsertion is done. This is a sort operation, and it's slow.
Don't abuse the && operator like that. There's nothing wrong with using nested if() statements.

Also, put those keys in an associative list. They will be easier to use that way.
var/tmp/list/shiftkeys = list(
"1" = "!",
"2" = "@",
"3" = "#",
"4" = "$",
"5" = "%",
"6" = "^",
"7" = "&",
"8" = "*",
"9" = "(",
"0" = ")",
"-" = "_",
"=" = "+",
"\[" = "{",
"\]" = "",
"\\" = "|",
";" = ":",
"'" = "\"",
"," = "<",
"." = ">",
"/" = "?")

// I hate using braces.
proc/ProcessText(key){
if(shifting){
for(var/keychar in shiftkeys){
if(key == keychar){
return shiftkeys[keychar]
}
}
. = key
}
}



A switch() statement can make your code more efficient, although depending on the format of your msg string, it may not work in this case.
proc/CheckAdminCommand(mob/Player/Owner, msg){
if(Owner.isadmin){
// This little dot holds the default return value.
// It can replace all but one of those return statements.
. = 1
switch(msg){
if("/reboot"){
world.Reboot()
}
if("/kick"){
msg = replacetext(msg, "/kick ", "")
Owner.Boot(msg)
}
if("/mute"){
msg = replacetext(msg, "/mute ", "")
Owner.Mute()
}
if("/unmute"){
msg = replacetext(msg, "/unmute ", "")
Owner.UnMute()
}
if("/ban"){
msg = replacetext(msg, "/ban ", "")
Owner.Ban()
}
if("/unban"){
msg = replacetext(msg, "/unban ", "")
Owner.UnBan()
}
if("/summon"){
msg = replacetext(msg, "/summon ", "")
Owner.Summon_Player()
}
if("/teleport"){
msg = replacetext(msg, "/teleport ", "")
Owner.Teleport()
}
if("/who"){
Owner.Who()
var/players
var/cnt
for(var/mob/Player/m in world){
players += "[m.name], "
cnt++
}
players = copytext(players,1,lentext(players)-1)
_message(Owner, "Players online:", "#FFFFFF")
_message(Owner, players, "#FFFFFF")
if(cnt == 1){
_message(Owner, "[cnt] player online.", "#FFFFFF")
}
else{
_message(Owner, "[cnt] players online.", "#FFFFFF")
}
}
else{
return 0
}
}
}
}
In response to Multiverse7
Just an aside, but you don't need to use \ when breaking up list elements across different lines. The following is perfectly fine:

var/list/whatever = list(
"hello",
"world",
"dream",
"maker"
)

In response to LordAndrew
That's strange. I seem to remember that failing when I tried it in the past. Maybe I'm just paranoid from using preprocessor macros so much.
Thank you guys for the help! I'll take a look when I get home.