<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Adam Frisby &#187; microthreads</title>
	<atom:link href="http://www.adamfrisby.com/blog/tag/microthreads/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.adamfrisby.com/blog</link>
	<description>ZOMGWTFHAI</description>
	<lastBuildDate>Sat, 26 Dec 2009 07:02:09 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>MRM: Microthreading Functions</title>
		<link>http://www.adamfrisby.com/blog/2009/04/mrm-microthreading-functions/</link>
		<comments>http://www.adamfrisby.com/blog/2009/04/mrm-microthreading-functions/#comments</comments>
		<pubDate>Fri, 24 Apr 2009 06:14:19 +0000</pubDate>
		<dc:creator>Adam Frisby</dc:creator>
				<category><![CDATA[OpenSim]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[microthreads]]></category>
		<category><![CDATA[mrm]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://www.adamfrisby.com/blog/?p=209</guid>
		<description><![CDATA[When running an infinite loop or other computationally expensive function, you will often want to release processing time back to the region to avoid causing undue &#8216;lag&#8217;. For instance &#8211; in a sim with 4,000 colour changing scripts, each will be trying to pummel the CPU simultaneously to get their updates onccuring.
What ends up happening [...]]]></description>
			<content:encoded><![CDATA[<p>When running an infinite loop or other computationally expensive function, you will often want to release processing time back to the region to avoid causing undue &#8216;lag&#8217;. For instance &#8211; in a sim with 4,000 colour changing scripts, each will be trying to pummel the CPU simultaneously to get their updates onccuring.</p>
<p>What ends up happening is each will run for a fairly long period of time until broken up by a processing expensive &#8220;thread switch&#8221; at which point the next gets a long run before going to the next and the next and the next, or alternatively &#8211; none will finish and only one will be running.</p>
<p>The following diagram explains this in action &#8211; script A runs until there is an expensive thread switch, at which point script B will commence operation. You can manually force a thread switch through the use of the &#8220;llSleep(0)&#8221; statement in LSL, however the cost of switching threads is still present.</p>
<div id="attachment_210" class="wp-caption aligncenter" style="width: 520px"><img class="size-full wp-image-210" title="Script Normal Threading" src="http://www.adamfrisby.com/blog/wp-content/uploads/mt_thread.png" alt="Fig 1. Normal Threaded Scripting" width="510" height="400" /><p class="wp-caption-text">Fig 1. Normal Threaded Scripting</p></div>
<p>Microthreading allows you to say &#8220;You can pause and give time to another script&#8221; &#8211; in a way that is very lightweight and easy for the runtime VM. You manually insert breakpoints into the script which define points between the &#8216;tasklets&#8217;, at these points the VM can switch between runtime contexts without any penalty. As a result you can have thousands of them without problem; when running time is divided between all the running threads evenly &#8211; broken up at the tasklet borders.</p>
<p>The following diagram shows the same as above, in a microthreading environment.</p>
<div id="attachment_211" class="wp-caption aligncenter" style="width: 520px"><img class="size-full wp-image-211" title="Microthreaded Environment" src="http://www.adamfrisby.com/blog/wp-content/uploads/mt_micro.png" alt="Fig 2. Microthreaded Runtime" width="510" height="400" /><p class="wp-caption-text">Fig 2. Microthreaded Runtime</p></div>
<p>C# supports a limited form of microthreading via something called the &#8220;<a href="http://msdn.microsoft.com/en-us/library/9k7k7cf0(VS.80).aspx">yield</a>&#8221; keyword &#8211; and a lot of people have recognised you can use it to <a href="http://blogs.msdn.com/matt_pietrek/archive/2004/07/26/197242.aspx">build a state machine</a> &#8212; the basis of microthreading. Where we apply this to MRM is with some additional keywords.</p>
<p>The basic C# microthreading can be implemented in MRM without any additional work &#8211; however there is a significant manual cost in typing the construction of a microthreaded function. I have added two new keywords to MRM scripts today, which map to the C# yield statements.</p>
<p>The first is &#8220;microthreaded&#8221; &#8211; this keyword is inserted between the public/private/protected/internal keywords at the beggining of the function, and the variable type.For example, &#8220;private microthreaded void MyFunction(&#8230;) {&#8221;. Microthreaded functions can only work on functions with a no return type (void) &#8211; and internally it works by replacing &#8220;microthreaded void&#8221; with &#8220;IEnumerable&#8221;.</p>
<p>The second important keyword is &#8220;relax&#8221; &#8211; this keyword is defined as a breakpoint &#8211; an area where the VM can switch into another microthread without a penalty. There is a very small cost in placing these statements into your code, so consider placing them liberally. Place them inside of any loops or other routines which have a total processing time in excess of 2 milliseconds.</p>
<p>The relax keyword can only be placed inside of functions marked microthreaded &#8211; and you cannot call microthreaded functions directly (as in &#8220;Function(params)&#8221;). You must place microthreaded functions into the host scheduler marked as &#8216;Host.Microthreads.Run(myfunc(params));&#8217;</p>
<p>Another important note is that microthreaded functions will run asynchronously to your code, so do not expect &#8220;Microthreads.Run(&#8230;)&#8221; to block, consider it more a &#8216;Microthreads.ScheduleToRun(&#8230;)&#8217;. If you take these penalties into consideration however, these Microthreads can provide an excellent way to optimize your scripting and write coroutines relatively easily and quickly.</p>
<p>By default, the MRM VM will run 1,000 microthread tasklets per frame (or optimally 45,000 per second), this can be tweaked from inside of MRMModule.cs, however will eventually move into the OpenSim.ini [MRM] section.</p>
<p>The following is an example script that uses MRM microthreads.</p>
<textarea name="code" class="c#:nocontrols" cols="60" rows="10">
//MRM:C#
using System.Collections;
using System.Collections.Generic;
using OpenSim.Region.OptionalModules.Scripting.Minimodule;

namespace OpenSim
{
    class MiniModule : MRMBase
    {
		public microthreaded void MicroThreadFunction(string testparam) 
		{
			Host.Object.Say("Hello " + testparam);
			
			relax; // the 'relax' keyword gives up processing time.
				   // and should be inserted before, after or in
				   // any computationally "heavy" zones.
			
			int c = 500;
			while(c-- < 0) {
				Host.Object.Say("C=" + c);
				relax; // Putting 'relax' in microthreaded loops
					   // is an easy way to lower the CPU tax
					   // on your script.
			}
			
		}

        public override void Start()
        {
            Host.Microthreads.Run(
					MicroThreadFunction("World!")
				);
        }
        
        public override void Stop()
        {
            
        }
    }
}
</textarea>
<p>Enjoy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.adamfrisby.com/blog/2009/04/mrm-microthreading-functions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
