mIRC Home    About    Download    Register    News    Help

Print Thread
#256019 12/12/15 09:44 PM
R
rafasantos555
rafasantos555
R
I wanted know some tips to organize better my codes.

I think my script is too slow, consuming 40k+ of memory

Idk if the codes are the problem.

So i wanted know if there are better ways to put the codes to be faster to process/read them.

#256020 12/12/15 10:18 PM
Joined: Jan 2004
Posts: 1,330
L
Hoopy frood
Offline
Hoopy frood
L
Joined: Jan 2004
Posts: 1,330
Can't tell you what's better without a basis.

#256021 13/12/15 02:34 AM
Joined: Aug 2003
Posts: 325
W
Fjord artisan
Offline
Fjord artisan
W
Joined: Aug 2003
Posts: 325
Originally Posted By: rafasantos555
I wanted know some tips to organize better my codes.

I think my script is too slow, consuming 40k+ of memory

Idk if the codes are the problem.

So i wanted know if there are better ways to put the codes to be faster to process/read them.
Like Loki said, hard to say without having some idea as to the code itself.

There are a few things to try though.

- For aliases that are treated as identifiers very often, have those near the top of the script.
- Limit use to files when possible. If your script is reading files constantly, that can slow things down. For things that are necessary, have them in memory somehow, either as variables or in hash tables. For example, if the script is looking for certain input to respond to, what it would check for should be in memory. What it needs to respond with could be in a file. If it checks and doesn't need to 'react' then it didn't do an unnecessary read of a file.
- Look at how any loops are being handled and see if there is a different way to accomplish the goal that might be faster.
- Re-evaluate the process when the script is activated, such as parsing input from a channel. If there are any requirements that need to be met for the script to kick in, have those requirements checked near the beginning. OP's only? Check if the user is an OP before it does a bunch of other stuff that would be a waste if the person isn't an OP.
- Try to determine what parts of the script is causing the lag. If you have multiple scripts, try unloading one at a time until you need a boost in responsiveness. Find the problem script (and the problem area) instead of trying to debug the entire thing as a whole.
- If it's all in one giant script, see if you can break things down into a few separate scripts.
- Consider how many timers you're using, especially if you're using the '-h' option for any timers, as that can cause issues.

If you know of a particular alias/event in your script that is causing issues, post the code here so others can pick through it and give you feedback with possible improvements.

#256022 13/12/15 03:11 AM
Joined: Apr 2010
Posts: 964
F
Hoopy frood
Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 964
To expand what Wolfie said and to add a few things:

Originally Posted By: Wolfie
For aliases that are treated as identifiers very often, have those near the top of the script.

Do this for all custom aliases that are used often, not just those that are used as identifers. Furthermore, change the script order(alt+r -> "file" -> order) so scripts with said aliases are first.

Originally Posted By: Wolfie
Limit use to files when possible.

Limit the use of files as DATA STORES (not the number of script files you have). Consider using Hash Tables which are fastest to access or Ini Files which are cached in memory when first accessed. If you must use a text file and are reading it from a loop consider using an alternative such as /filter, /loadBuf, or File Handling related commands & identifers(/fopen, /fclose, $fread, etc)

Originally Posted By: Wolfie
If it's all in one giant script, see if you can break things down into a few separate scripts.

This can be done by: alt+r -> file -> load.


Originally Posted By: Wolfie
Re-evaluate the process when the script is activated, such as parsing input from a channel. If there are any requirements that need to be met for the script to kick in, have those requirements checked near the beginning.

In event processing, try to narrow down the trigger as far as possible before getting into the body of the handler
Code:
;instead of this
on *:TEXT:*:#: if ($1 == !command) { stuff }

;do this:
on *:TEXT:!command:#:{ stuff }

Furthermore, its better to use multiple events with similar code for different commands than it is to use a single event to handle multiple things
Code:
;instead of this
on *:TEXT:*:#:{
  if ($nick isop #) { 
    if ($1 == !command1) { stuff }
    elseif ($1 == !command2) { stuff2 }
  }
}

; use this:
on *:TEXT:!command1:#:{
  if ($nick isop #) { stuff }
}
on *:TEXT:!command2:#:{
  if ($nick isop #) { stuff }
}



If all else fails, you can use specific prefixes to bypass mIRC's lookup of custom aliases when using a native command or identifer is desired.
Code:
;Bypasses lookup for custom commands by using the ! prefix
!msg # message
.!msg # message

;Bypass lookup for custom identifiers by using the ~ prefix
echo -a $~me



-------------------------------------------

With all of that said, to really help you narrow down your problem areas, we'd need to have far more context such as the script(s) your are using, networks you are connected to, and the channels you are on pertaining to said networks






Last edited by FroggieDaFrog; 13/12/15 06:58 AM.
Joined: Aug 2003
Posts: 325
W
Fjord artisan
Offline
Fjord artisan
W
Joined: Aug 2003
Posts: 325
Originally Posted By: FroggieDaFrog
Originally Posted By: Wolfie
Re-evaluate the process when the script is activated, such as parsing input from a channel. If there are any requirements that need to be met for the script to kick in, have those requirements checked near the beginning.

In event processing, try to narrow down the trigger as far as possible before getting into the body of the handler
Code:
;instead of this
on *:TEXT:*:#: if ($1 == !command) { stuff }

;do this:
on *:TEXT:!command:#:{ stuff }

Furthermore, its better to use multiple events with similar code for different commands than it is to use a single event to handle multiple things
Code:
;instead of this
on *:TEXT:*:#:{
  if ($nick isop #) { 
    if ($1 == !command1) { stuff }
    elseif ($1 == !command2) { stuff2 }
  }
}

; use this:
on *:TEXT:!command1:#:{
  if ($nick isop #) { stuff }
}
on *:TEXT:!command2:#:{
  if ($nick isop #) { stuff }
}
Actually that's bad advice. Multiple event handlers means extra parsing and the idea is to reduce code as well.

Code:
ON *:TEXT:*:#:{
  if ( !* iswm $strip($1-) || !$nick($chan,$nick,o) ) { return }

  (cont)

This is better because you are checking one time if the person is an OP and ending the processing if it's not a !command (not to mention not additional event processing).

A method I use to replace if/then conditions for commands is to use a custom alias format to handle things. For example, !command1 !command2 and !command3 would be aliases like so:
Code:
alias op.!command1 { stuff }
alias op.!command2 { stuff }
alias op.!command3 { stuff }
Then in the ON TEXT trigger, check if the alias exists and if it does, call on it, like so...
Code:
  (cont)

  while ( $strip($1) != $1 ) { tokenize 32 $strip($1) $2- }
  VAR %command = $+(op.,$1)
  IF ( $isalias(%command) ) { %command $2- }
}

That little bit of code (connected by the 'cont' lines) is quite versatile and efficient.

If you still think doing multiple ON TEXT events is better, then consider this. Each ON TEXT event is comparing the actual text against the required text. If you have 20 events, that's 20 comparisons. By doing it in one event then checking if it would ever match (the "!* !iswm $strip($1-)" part), it's only doing one pass on it. Not only that but if someone's using a script that sends out color codes when they type, their attempts to use a !command would get ignored (thus the $strip identifier, so it doesn't get ignored). There's also one check to make sure it's an OP, so there isn't a need to make sure it's included with every command.


smile

Joined: Apr 2010
Posts: 964
F
Hoopy frood
Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 964
Originally Posted By: Wolfie
Actually that's bad advice. Multiple event handlers means extra parsing and the idea is to reduce code as well.


It is faster/better to narrow down the event handler as I explained than to have a single event handling multiple triggers. The reason is if you have a single "catch-all" event the handler will still trigger for EVERY received message leaving the scripted body to narrow down when the script should activate. Where as multiple event handlers make use of mIRC's internals to avoid needless scripted(I.g. slow) handling.


Assuming we receive the following messages from users in a channel
Code:
<john> Hi, anyone around?
<bill> Hello, ask your question
<@tim> !example1
<john> this is example inputs
<@George> !example2


The following will trigger 5 times even though its only needed twice:
Code:
on *:TEXT:*:#:{
  if ($nick isop #)
    if ($1- == !example1) {
      stuff
    }
    elseif ($1- == !example2) {
      stuff
    }
  }
}



Verses the following where each event will only trigger once
Code:
on *:TEXT:!example1:#:{
  if ($nick isop #) {
    stuff  
  }
}

on *:TEXT:!example2:#:{
  if ($nick isop #) {
    stuff
  }
}


Last edited by FroggieDaFrog; 13/12/15 07:42 AM.
Joined: Aug 2003
Posts: 325
W
Fjord artisan
Offline
Fjord artisan
W
Joined: Aug 2003
Posts: 325
Originally Posted By: FroggieDaFrog
It is faster/better to narrow down the event handler as I explained than to have a single event handling multiple triggers. The reason is if you have a single "catch-all" event the handler will still trigger for EVERY received message leaving the scripted body to narrow down when the script should activate. Where as multiple event handlers make use of mIRC's internals to avoid needless scripted(Ie slow) handling.
I like how you completely ignored the code I provided to try to make your way seem better while also making a mess up of your own. Why use a conditional statement to check if the person is an op and then (do whatever) if they are instead of checking if they aren't and (if they aren't) doing a return to exit out of that event?

Also, if someone wants to have, say 30 commands, that's 30 event handlers, each needing their own 'isop' check and being unreliable for working under certain conditions. So, unreliable, lots more code which means more room for error and more bloat to slow things down.

Joined: Apr 2010
Posts: 964
F
Hoopy frood
Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 964
The code was specifically to show how mIRC's internals will NOT trigger the specified events at all if they do not match the "!command" specified in the event handler. My 'setup' code does exactly as your code does -- only continue with the script if the user is op and a specific !command was issued -- just differently. What part did I overlook/ignore and where did I mess up?

Why is 'my' method better than 'yours'? 'My' scripted event body ONLY triggers for the specified command; it makes use of mIRC's internal event handling to eliminate messages -- as best as possible -- that do not fit with what I wish to do.

Where as a catch-all event will still trigger for EVERY message received; even if there is no command to process. Yes you exit at the first possible moment, but that still requires invocation of the script engine for EVERY message received.

---

As far as multiple-event parsing: mIRC, internally, registers scripted events when mIRC/scripts are first loaded. It does NOT scan each file at the time of an event and figure out which event(s) to trigger. It already has them registered and knows which to trigger for a given received message

Last edited by FroggieDaFrog; 13/12/15 07:46 AM.
Joined: Aug 2003
Posts: 325
W
Fjord artisan
Offline
Fjord artisan
W
Joined: Aug 2003
Posts: 325
Originally Posted By: FroggieDaFrog
The mangling(where?) of code was specifically to show how mIRC's internals will NOT trigger the specified events at all if they do not match the "!command" specified in the event handler. My 'setup' code does exactly as your code does -- only continue with the script if the user is op and a specific !command was issued -- just differently. What part did I overlook/ignore?

Why is 'my' method better than 'yours'? 'My' scripted event body ONLY triggers for the specified command; it makes use of mIRC's internal event handling to eliminate messages -- as best as possible -- that do not fit with what I wish to do.

Where as a catch-all event will still trigger for EVERY message received; even if there is no command to process. Yes you exit at the first possible moment, but that still requires invocation of the script engine for EVERY message received.

---

As far as multiple-event parsing: mIRC, internally, registers scripted events when mIRC/scripts are first loaded. It does NOT scan each file at the time of an event and figure out which event(s) to trigger. It already has them registered and knows which to trigger for a given received message
What if someone is using a script that sends out color codes when they type something? What if there are 30 or so events? Each time you make a new event, you have to duplicate a lot of code to ensure it works when it's supposed and how it's supposed to.

Joined: Apr 2010
Posts: 964
F
Hoopy frood
Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 964
General
  • Break up large scripts into multiple script files (alt+r > "File" > "New")
  • Put aliases that are used excessively at the top of the script file.
  • Put scripts with aliases that are used excessively at the top of the script order (alt+r > "File" > "Order")



Coding
  • Limit file read/writes 1
  • Limit event exposure by being as specific as possible with the event definition and break up large event bodies that handle multiple triggers into separate events 2
  • Group similar processing of multiple /timers together under a single timer; Avoid using the -h switch for timers when possible.
  • Limit various forms of scripted looping
  • Not all if-statement formats process at the same speed; pick accordingly
  • When using native commands or identifers use ! or ~ prefixing to bypass mIRC's custom alias lookup 3
  • 'if statements' are faster than '$iif()'s 4
  • If using $gettok on the same set of data multiple times look into using /tokenize and $n instead.



Notes
  1. Instead of using flat-files as a data storage look into Hash Tables(which are stored in memory; can be saved/loaded from file) or INI files(which are cached in memory after the first access). If you must use a flat file for a data-store look into using /filter /loadbuf or the File Handling commands & identifers(/fopen $fread /fclose) when accessing the file via a loop
  2. Dividing up events into separate triggers makes the processing faster, ensures your code is module, and makes your code more human-readable
  3. For instances where you wish to use a native command prefix the command with "!", and for native identifers insert a "~" after the $:
    Code:
    !echo -a $~me
  4. Bench marks for if vs $iif:
    Click to reveal..
    Code:
    iterations: 1000000
    if vs $iif: 50.36s vs 81.234s


    Code:
    alias -l bench1 {
      if ($1) return $true
      return $false
    }
    alias -l bench2 {
      return $iif($1, $true, $false)
    }
    
    alias bench_1 {
      !var %x $1
      !var %z $~ticks
      while (%x) {
        !noop $bench1(0)
        !noop $bench1(1)
        !dec %x
      }
      !return $~calc($~ticks - %z)
    }
    alias bench_2 {
      !var %x $1
      !var %z $~ticks
      while (%x) {
        !noop $bench2(0)
        !noop $bench2(1)
        !dec %x
      }
      !return $~calc($~ticks - %z)
    }
    alias benchit {
      var %a = $bench_1($1)
      var %b = $bench_2($1)
    
      echo -a iterations: $1
      echo -a if vs $!iif: $calc(%a / 1000) $+ s vs $calc(%b / 1000) $+ s
    }

Joined: Apr 2010
Posts: 964
F
Hoopy frood
Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 964
So, instead of arguing for the sake of argument I sat down and came up with the best bench-mark I could for single catch-all event vs multiple single-case events... and it turns out neither of us are right nor wrong: both methods are roughly the same speed (in fact, at this point, I'd be willing to chock the difference up to displaying the text).

For multiple single-case events:
Code:
/benchit 5000
Done: 78.141s


For single multi-case events:
Code:
/benchit 5000
Done: 78.165s



Methodology:
  1. Create a fresh mIRC instances
  2. Connect to a single server
  3. Maximize windows within the MDI area
  4. Join #benchit_test
  5. Activate status window(so the channel window is hidden)
  6. /clear the status window
  7. Install first benchmark script
  8. Issue /benchit 5000
  9. After it ends, unload first script
  10. Load second script
  11. Clear the channel window
  12. Reactivate the status window
  13. /clear the status window
  14. Issue /benchit 5000


bench mark for multiple single-case events
Code:
alias benchit_done {
  echo -a Done: $calc($1 /1000) $+ s
  unset %benchit_ticks
}
alias benchit {
  echo -a /benchit $1
  var %x $1
  while (%x) {
    .parseline -iqptu0 :benchit!benchit@bench.it PRIVMSG #benchit_test :!benchit $+ %x
    dec %x
  }
  !set %benchit_ticks $~ticks
}
on *:TEXT:!benchit1:#benchit_test: benchit_done $~calc($~ticks - %benchit_ticks)
on *:TEXT:!benchit2:#benchit_test: !noop
on *:TEXT:!benchit3:#benchit_test: !noop
on *:TEXT:!benchit4:#benchit_test: !noop
on *:TEXT:!benchit5:#benchit_test: !noop
on *:TEXT:!benchit6:#benchit_test: !noop
on *:TEXT:!benchit7:#benchit_test: !noop
on *:TEXT:!benchit8:#benchit_test: !noop
on *:TEXT:!benchit9:#benchit_test: !noop
on *:TEXT:!benchit10:#benchit_test: !noop


Bench mark for single multiple-case event
Code:
alias benchit_done {
  echo -a Done: $calc($1 /1000) $+ s
  unset %benchit_ticks
}
alias benchit {
  echo -a /benchit $1
  var %x $1
  while (%x) {
    .parseline -iqptu0 :benchit!benchit@bench.it PRIVMSG #benchit_test :!benchit $+ %x
    dec %x
  }
  !set %benchit_ticks $~ticks
}
on *:TEXT:*:#benchit_test:{
  if (!benchit1 == $1) benchit_done $~calc($~ticks - %benchit_ticks)
  elseif (!benchit2 == $1) !noop
  elseif (!benchit3 == $1) !noop
  elseif (!benchit4 == $1) !noop
  elseif (!benchit5 == $1) !noop
  elseif (!benchit6 == $1) !noop
  elseif (!benchit7 == $1) !noop
  elseif (!benchit8 == $1) !noop
  elseif (!benchit9 == $1) !noop
  elseif (!benchit10 == $1) !noop
}

Last edited by FroggieDaFrog; 13/12/15 08:34 PM.

Link Copied to Clipboard