mIRC Homepage
Posted By: Solo1 script really slow - 21/11/07 04:59 PM
greetings, if anyone has sometime to rewrite this little snippet it would be appreciated as it seems really slow and i feel it could be done alot better.

Code:
alias clonescan {
  if ($ial == $false) .ial on 
  var %i 1,%chan $1
  if (!$window($+(@clones,.,$network,.,%chan))) { window -Czd $+(@clones,.,$network,.,%chan) 100 50 690 460 | titlebar $+(@clones,.,$network,.,%chan) Clones list for $+($network,:) $nick(%chan,0) users currently on %chan | font $+(@clones,.,$network,.,%chan)) 12 arial bold }
  if (%chan !ischan) { aline -p $+(@clones,.,$network,.,%chan) 4ERROR no such channel $iif(%chan,as %chan) | return }
  while (%i <= $nick(%chan,0)) {
    if ($ialchan($address($nick(%chan,%i),2),%chan,0) > 1) && ($address($nick(%chan,%i),2) !isin %addr) {
      var %addr = %addr $address($nick(%chan,%i),2)
      aline -p 12 $+(@clones,.,$network,.,%chan) $timestamp $chr(42) Found ( $+ $ialchan($address($nick(%chan,%i),2),%chan,0) $+ ) Clones in $+($chr(40),%chan,$chr(41)) from ( $+ $gettok($address($nick(%chan,%i),2),2,64) $+ )
      var %cnt 1
      while (%cnt <= $ialchan($address($nick(%chan,%i),2),%chan,0)) {
        aline -p $+(@clones,.,$network,.,%chan) $timestamp $chr(42) $+(%cnt,.) $ialchan($address($nick(%chan,%i),2),%chan,%cnt).nick
        inc %cnt
      }
      aline -p $+(@clones,.,$network,.,%chan) -
    }
    inc %i
  }
  if (!%addr) { aline $+(@clones,.,$network,.,%chan) $timestamp 4,1No clones found on %chan }
}
Posted By: Wims Re: script really slow - 21/11/07 05:18 PM
You use a while loop to check each address on the channel, so if you have 300 nick on a channel, it's normal that it take time.

You should use the /names #channel to get each nick
Posted By: Bekar Re: script really slow - 21/11/07 09:02 PM
Code:
alias clonescan {
  if ($ial == $false) {
    ; note: if the IAL isn't on before this, ouch!  Nothing will be in the IAL!
    .ial on 
    return
  }
  var %i = 1, %chan = $1, %win = $+(@clones,.,$network,.,%chan), %addr
  if (!$window(%win)) {
    window -Czd %win 100 50 690 460
    titlebar %win Clones list for $+($network,:) $nick(%chan,0) users currently on %chan
    font %win 12 arial bold
  }
  if (%chan !ischan) {
    aline -p %win 4ERROR no such channel $iif(%chan,as %chan)
    return
  }
  while ($nick(%chan, %i)) {
    var %smask = $address($v1,%i)
    if ($ialchan(%smask,%chan,0) > 1) && (%smask !isin %addr) {
      %addr = %addr $address($nick(%chan,%i),2)
      aline -p 12 %win $timestamp $chr(42) Found ( $+ $ialchan(%smask,%chan,0) $+ ) Clones in $+($chr(40),%chan,$chr(41)) from ( $+ $gettok(%smask,2,64) $+ )
      var %cnt = 1
      while ($ialchan(%smask,%chan,%cnt)) {
        aline -p %win $timestamp $chr(42) $+(%cnt,.) $gettok($v1, 1, 33)
        inc %cnt
      }
      aline -p %win -
    }
    inc %i
  }
  if (!%addr) {
    aline %win $timestamp 4,1No clones found on %chan
  }
  else {
    aline %win $timestamp  4,1Scan on %chan complete!
  }

}

So, why would this be faster?

A few reasons:

Every time through the loop, you were re-evaluating the window name a minimum of 4 times. 300 people in a channel means a minimum of 1200 evaluations of that one string, which isn't changing. Slow down.

With that in mind, we do the same thing with the $address($nick(%chan,%i), 2). This is an IAL lookup to begin with, so instead of doing a few as possible lookups, you were doing double, which in a single pass would be something like 11 lookups. This cuts it in half to 3-4.

The while loops were changed as well, so that the full count isn't required for every-iteration-of-the-loop.

Anyway, my tests of the above code in a 370 user channel takes about a second on my underclocked P4.
Posted By: Horstl Re: script really slow - 21/11/07 09:19 PM
Here's a quite similar scanner I made some time ago; for this post I did a bad translation of the output, added some comments, removed my own hotlinks, separated the colouring from the theme to variables etc - maybe it's usefull none the less...
The uper part is the scanning thingie as you'll see, the lower (messy) part is about output formatting :X

My own approach is far from being "speed optimized", but looking at yours some thougts:
- a-lining is faster if the window is hidden
- "while (%i <= $nick(%chan,0))" why not "while ($nick,%chan,%i)"? Then you could use $ifmatch / $v1 to refer to the matching nickname of that loop directly
- you are refering to "$address($nick(%chan,%i),2)" many times, you could set this to a var, do the same with the window name


Code:
; clonescan2 <#channel>
alias clonescan2 {
  var %start = $ticks, %nicks = $ialchan(*,$1,0), %nick.num = 1
  var %prefixreg = $+(/,$chr(40),[,$prefix,],$chr(41),/g), %clones, %lines, %groups
  ; • here you can modify the display colours •
  var %c1 = 07, %c2 = 11, %c3 = 10, %c4 = 14

  ; ••• cycle all nicks of that channel •••
  while ($nick($1,%nick.num)) {
    var %host = $mask($ialchan($v1,$1,1),2), %matches = $ialchan(%host,$1,0)
    ; • clones found (host has more than 1 nicks on chan) •
    if (%matches > 1) {
      ; • add the current nick to the variable of nicks for that host, inc count of total clones •
      var %clones. [ $+ [ %host ] ] $($+(%,clones.,%host),2) $nick($1,%nick.num).pnick
      inc %clones
      ; • if all clones for a host had been found •
      if ($numtok($($+(%,clones.,%host),2),32) == %matches) {
        ; • prepare the lines for the output (stored as variables) •
        var %makelines = $ceil($calc(%matches /3)), %nr = 1
        while (%nr <= %makelines) {
          inc %lines
          ; • in this messy line, the values are coloured etc •
          var %line. [ $+ [ %lines ] ] $chr(9) $iif((%nr == 1),$+ %c3 $+ $numtok($($+(%,clones.,%host),2),32)) $chr(9) $iif((%nr == 1),$gettok(%host,2,64)) $chr(9) %c3 $+ $&
            $gettok($replace($regsubex($($+(%,clones.,%host),2),%prefixreg,$+(%c1,\t,%c3)),$chr(32),$+($chr(44),$chr(32)) ),$+($calc((%nr -1) *3 +1),-,$calc(%nr *3)),32)
          inc %nr
        }
        inc %groups
        inc %lines
        var %line. [ $+ [ %lines ] ] $chr(9) %c4 $+ $str(-,163)
      }
    }
    inc %nick.num
  }
  ; ••• output •••
  ; • create window (dynamic size) •
  var %wind = $+(@,Clonescan,$chr(160),$1)
  window -hk0z -t1,4,20 %wind -1 -1 900 $round($calc(18 * $iif((%lines),%lines,0) +128),0) Arial 15
  ; • title •
  aline %wind $+($chr(9) %c3,$str(•,40) $str($chr(160),3) %c2,Clonescan %c3,at %c2,$1 %c3,$str($chr(160),3) $str(•,40))
  aline %wind $chr(9)
  ; • output "total" / "no clones" / scan time / time and date • 
  aline %wind $chr(9) $&
    $iif((%clones),$+(%c3,Total: $chr(9) $chr(91),%c2,%clones,%c3,$chr(93)),$chr(9) %c3 $+ No) Clones $+(%c3,of $chr(91),%c2,%nicks,%c3,$chr(93) Users) $iif((%clones),$+(in $chr(91),%c2,%groups,%c3,$chr(93)) $iif((%groups == 1),Group.,Groups.),found.) $&
    $chr(9) %c4 $+ (Scan time: $round($calc(($ticks - %start) /1000),2) Seconds) %c3 $+ $+([,$date(dd.mm.yyyy),$chr(44) $time,])
  aline %wind $chr(160)
  ; • output of the clones list •
  if (%clones) {
    aline %wind %c2 $+ $chr(2) $chr(9) Clones $chr(9) Host $chr(9) Nicks
    var %num = 1
    while ($($+(%,line.,$calc(%num +1)),2)) {
      aline %wind $($+(%,line.,%num),2)
      inc %num
    }
  }
  ; • end of output, show window •
  aline %wind $chr(9) %c4 $+ $str(-,163)
  window -ra %wind
}
Posted By: Bekar Re: script really slow - 21/11/07 09:26 PM
*chuckles* same thoughts ;P
Posted By: Wims Re: script really slow - 21/11/07 10:12 PM
I think the best method is the /names, because you only need one while, using $*...
Here is my method, i use bekar's code :

Code:
alias clonescan {
  if ($ial == $false) {
    .ial on 
    return
  }
  var %chan = $1, %win = $+(@clones,.,$network,.,%chan)
  if (!$window(%win)) {
    window -Czd %win 100 50 690 460
    titlebar %win Clones list for $+($network,:) $nick(%chan,0) users currently on %chan
    font %win 12 arial bold
  }
  if (%chan !ischan) {
    aline -p %win 4ERROR no such channel $iif(%chan,as %chan)
    return
  } 
  set -u2 %names.win %win
  names %chan
}

raw 353:*:if (%names.win) { var %chan $3 | tokenize 32 $remove($4-,@,%,+) | haltdef | loopadd %chan $* }
raw 366:*:{
  if (%names.win) {
    haltdef
    aline %names.win $timestamp 4,1 $+ $iif(%names.addr,Scan on $2 complete!,No clones found on $2)
    unset %names.*
  }
}

alias loopadd {
  var %smask $address($2,2) ,%c $1
  if ($ialchan(%smask,%c,0) > 1) && (%smask !isin %names.addr) {
    set %names.addr %names.addr $v1
    aline -p 12 %names.win $timestamp $chr(42) Found ( $+ $ialchan(%smask,$1,0) $+ ) Clones in $+($chr(40),%c,$chr(41)) from ( $+ $gettok(%smask,2,64) $+ )
    var %cnt 1
    while ($ialchan(%smask,%c,%cnt)) {
      aline -p %names.win $timestamp $chr(42) $+(%cnt,.) $gettok($v1,1,33)
      inc %cnt
    }
    aline -p %names.win -
  }
}

On a big channel (300 person...) this method is faster than a while and not freeze mirc.
Posted By: Bekar Re: script really slow - 21/11/07 10:22 PM
the hell?

IRCHighway #lurk: 1358 members. 3-4 seconds..

Just how big a channel are you wanting to use it on? In any case, waiting for a REPL_NAMES makes it go 'slower'.. wink
Posted By: Horstl Re: script really slow - 21/11/07 10:44 PM
The only advantage of "names" that I see is the de-freeze effect as you retrieve the nicks in packages, but it's not affecting the amount of processing (?)
1) loop all users (ialchan or names) and check their site for clones
2) if a site is present more than once (clones),add the nick to a group of that site
a) process the rest of the group instantly and skip this site later
or
b) process the nicks linear and add all other matches for a site to it's group
3) output the cloning nicks in groups
smile
Posted By: Wims Re: script really slow - 21/11/07 11:11 PM
Originally Posted By: Bekar
Just how big a channel are you wanting to use it on? In any case, waiting for a REPL_NAMES makes it go 'slower'.. ;\)
You're right, the worst is that i've already make some bench in the past and already seen that /names is slower than the loop, it's certainly the word *while* that remind me "no, it's slow!! smile "
Anyway thx for clarification.
Posted By: Solo1 Re: script really slow - 22/11/07 09:44 AM
Hi Bekar thanks for that, small problem is that at times it can pick up the same clones twice, anyway you can fix that please.
Posted By: Wims Re: script really slow - 22/11/07 10:12 AM
I think Bekar made some typo when he re-wrote your code.
Replace the while by this one

Code:
while ($nick(%chan, %i)) {
    var %smask = $address($v1,2)
    if ($ialchan(%smask,%chan,0) > 1) && (%smask !isin %addr) {
      %addr = %addr %smask
      aline -p 12 %win $timestamp $chr(42) Found ( $+ $ialchan(%smask,%chan,0) $+ ) Clones in $+($chr(40),%chan,$chr(41)) from ( $+ $gettok(%smask,2,64) $+ )
      var %cnt = 1
      while ($ialchan(%smask,%chan,%cnt)) {
        aline -p %win $timestamp $chr(42) $+(%cnt,.) $gettok($v1, 1, 33)
        inc %cnt
      }
      aline -p %win -
    }
    inc %i
  }


Posted By: Solo1 Re: script really slow - 22/11/07 11:41 AM
Thnaks Wims,

In really big channles i get /set: line too long (line 681, script1.mrc) because it cant set such a long variable, is there any way round this?
Posted By: Wims Re: script really slow - 22/11/07 12:05 PM
Yes, use hash table instead of variable :

Code:
alias clonescan {
  if ($ial == $false) {
    ; note: if the IAL isn't on before this, ouch!  Nothing will be in the IAL!
    .ial on 
    return
  }
  var %i = 1, %chan = $1, %win = $+(@clones,.,$network,.,%chan), %addr
  if (!$window(%win)) {
    window -Czd %win 100 50 690 460
    titlebar %win Clones list for $+($network,:) $nick(%chan,0) users currently on %chan
    font %win 12 arial bold
  }
  if (%chan !ischan) {
    aline -p %win 4ERROR no such channel $iif(%chan,as %chan)
    return
  }
  while ($nick(%chan, %i)) {
    var %smask = $address($v1,2)
    if ($ialchan(%smask,%chan,0) > 1) && (!$hget(addr,%smask)) {
      hadd -m addr %smask 1
      aline -p 12 %win $timestamp $chr(42) Found ( $+ $ialchan(%smask,%chan,0) $+ ) Clones in $+($chr(40),%chan,$chr(41)) from ( $+ $gettok(%smask,2,64) $+ )
      var %cnt = 1
      while ($ialchan(%smask,%chan,%cnt)) {
        aline -p %win $timestamp $chr(42) $+(%cnt,.) $gettok($v1, 1, 33)
        inc %cnt
      }
      aline -p %win -
    }
    inc %i
  }
  if (!$hget(addr)) {
    aline %win $timestamp 4,1No clones found on %chan
    
  }
  else {
    aline %win $timestamp  4,1Scan on %chan complete!
    hfree addr
  }
}


Edit : correct a mistake.
Posted By: sparta Re: script really slow - 22/11/07 01:34 PM
I noticed the code in here, and i tested it, working just fine, but i never seen a window using %win = $+(@clones,.,$network,.,%chan), %addr to be created, and i was fooling around a bit with the code, and i was wondering, any way to add a @menu to a window created that way? i tested to save $+(@clones,.,$network,.,%chan), %addr to a %var, then use menu %var .. and no luck, the %var is saved the same way the window is created, how come the menu dosent work for it?
Posted By: Horstl Re: script really slow - 22/11/07 01:53 PM
You can use wildcards and parse the window name smile
//window $+(@clones.,$network,.,$chan(1))
Code:
menu @clones.* {
  $iif(($gettok($active,2,46)  == $network),stuff with chan $gettok($active,3-,46)) : echo $active works
}


EDIT
In addition, if it's no list window ($sline), you could use a hotlink event to store the right-clicked line ("if ($mouse.key && 16) ... stuff with $hotline") temporarily (e.g. to a hash that will be destroyed if the @window is closed),and use this data in the menu definition. (Quite a hack, but it works well for me)
Posted By: sparta Re: script really slow - 25/11/07 10:27 AM
ty, got it to work.. smile
© mIRC Discussion Forums