You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ad...@apache.org on 2017/03/31 17:13:39 UTC

[2/7] incubator-mynewt-site git commit: 1) Updated Task and Priority Management tutorial: Uses defauilt main task instead of the blinky task for the examples. Updated the picture use main task. Removed Comparing Task Priority section. 2) Updated

1) Updated Task and Priority Management tutorial:
   Uses defauilt main task instead of the blinky task for the examples.
   Updated the picture use main task.
   Removed Comparing Task Priority section.
2) Updated Log module documentation


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/commit/19e0f48f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/tree/19e0f48f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/diff/19e0f48f

Branch: refs/heads/develop
Commit: 19e0f48ff80de0c727bb0c281707b0d1ecbc3f21
Parents: 3a6e4ff
Author: cwanda <wa...@happycity.com>
Authored: Wed Mar 29 19:16:48 2017 -0700
Committer: cwanda <wa...@happycity.com>
Committed: Wed Mar 29 19:16:48 2017 -0700

----------------------------------------------------------------------
 docs/os/modules/logs/logs.md           | 151 +++++++--------
 docs/os/tutorials/pics/task_lesson.png | Bin 12931 -> 23822 bytes
 docs/os/tutorials/tasks_lesson.md      | 273 ++++++----------------------
 3 files changed, 135 insertions(+), 289 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/19e0f48f/docs/os/modules/logs/logs.md
----------------------------------------------------------------------
diff --git a/docs/os/modules/logs/logs.md b/docs/os/modules/logs/logs.md
index 7da1a77..63ce68c 100644
--- a/docs/os/modules/logs/logs.md
+++ b/docs/os/modules/logs/logs.md
@@ -1,17 +1,31 @@
-## Mynewt Logging
-
-Apache Mynewt has a logging package (`apache-mynewt-core/sys/log`) to support
-logging of information within a Mynewt application.
+##Logging
 
+Mynewt log package supports logging of information within a Mynewt application.  It allows packages to define their own log streams with separate names.  It also allows an application to control the output destination of logs. 
 <br>
-
 ###Description
 
-Logging API is provided in `apache-mynewt-core/sys/log/include/log/log.h`.
+In the Mynewt OS, the log package comes in two versions:
+
+* The `sys/log/full` package implements the complete log functionality and API.
+
+* The `sys/log/stub` package implements stubs for the API.
 
-It allows packages to define their own log streams with separate 
-names.  It also allows an application to control the output destinations
-of logs. 
+Both packages export the `log` API, and any package that uses the log API must list `log` as a requirement  in its `pkg.yml` file as follows: 
+
+```no-highlight
+pkg.req_apis:
+    - log
+```
+
+<br>
+The application's `pkg.yml` file specifies the version of the log package to use.
+A project that requires the full logging capability must list the `sys/log/full` package as a dependency in its `pkg.yml` file:
+```no-highlight
+pkg.deps:
+    - sys/log/full
+```
+<br>
+You can use the `sys/log/stub` package if you want to build your application without logging to reduce code size.
 
 <br>
 
@@ -24,19 +38,19 @@ these at compile time to ensure the code size limits are met.
 
 A compiler flag `LOG_LEVEL` can be set  in your `target.cflags` or within
 your app `pkg.cflags` files to set the compile time log level.   The 
-log level are defined in `apache-mynewt-core/sys/log/include/log/log.h`
+log level are defined in `/sys/log/full/include/log/log.h`
 but must be added by number to your `yml` file.
 
 For example:
 
 ```no-highlight
-    pkg.cflags -DLOG_LEVEL=8
+    pkg.cflags -DLOG_LEVEL=3
 ```
 
 or 
 
 ```no-highlight
-    newt target set my_target cflags=-DLOG_LEVEL=8
+    newt target set my_target cflags=-DLOG_LEVEL=3
 ```
 
 would both set the compile-time log level to `LOG_LEVEL_ERROR`.  All logs
@@ -50,20 +64,18 @@ system.
 
 ### Log
 
-Each log stream requires a log structure to define its  logging properties.
-It is typical for modules to extern this structure.
-
+Each log stream requires a `log` structure to define its  logging properties. 
 <br>
 
 ### Log Handler
 
-To use logs, a log-handler is required, which is responsible for handling
-the I/O from the log.  The log package comes with two pre-built log handlers.
+To use logs, a log handler that handles the I/O from the log is required.  The log package comes with three pre-built log handlers:
 
 * console -- streams log events directly to the console port.  Does
 not support walking and reading.
 * cbmem -- writes/reads log events to a circular buffer.  Supports walking 
-and reading for access by `newtmgr` and shell commands.
+and reading for access by newtmgr and shell commands.
+* fcb -- writes/reads log events to a [flash circular buffer](/os/modules/fcb/fcb.md). Supports walking and reading for access by newtmgr and shell commands.
 
 In addition, it is possible to create custom log handlers for other methods.
 Examples may include
@@ -72,101 +84,96 @@ Examples may include
 * Flat flash buffer
 * Streamed over some other interface
 
-To use logging, you will not typically need to create your own log handler.
-You can use one of the two supplied above. 
+To use logging, you typically do not need to create your own log handler.  You can use one of the pre-built ones.
 
-In Mynewt today, each module will register its logs with a default log handler.
-Its up to the application to use or override this log handler for its 
-specific purposes.  See below for an example.
+A package or an application must define a variable of type `struct log` and register a log handler for it with the log package. It must call the `log_register()` function to specify the log handler to use:
 
-<br>
+```c
+log_register(char *name, struct log *log, const struct log_handler *lh, void *arg, uint8_t level)
 
-### Typical use of logging when writing an application 
+```
 
-When writing an application that is using other's log modules, you 
-may want to override their log handlers and log levels.
+The parameters are:
 
-Add the logging to your package file.
+* `name`- Name of the log stream.
+* `log` - Log instance to register,
+* `lh` - Pointer to the log handler. You can specify one of the pre-built ones: 
+    * `&log_console_handler` for console
+    * `&log_cbm_handler`  for  circular buffer 
+    * `&log_fcb_handler` for flash circular buffer
+* `arg` - Opaque argument that the specified log handler uses. The value of this argument depends on the log handler you specify:
+    * NULL for the `log_console_handler`.
+    * Pointer to an initialized `cbmem` structure (see `util/cbmem` package) for the `log_cbm_handler`.
+    * Pointer to an initialized `fcb_log` structure (see `fs/fcb` package) for the `log_fcb_handler`. 
 
-```no-highlight
-    pkg.deps:
-        - "@apache-mynewt-core/sys/log"
-```
+Typically, a package that uses logging defines a global variable, such as `my_package_log`, of type `struct log`. The package can call the `log_register()` function with default values, but usually an application will override the logging properties and where to log to. There are two ways a package can allow an application to override the values:
 
-<br>
+* Define system configuration settings that an application can set and  the package can then call the `log_register()` function with the configuration values.
+* Make the `my_package_log` variable external and let the application call the `log_register()` function to specify a log handler for its specific purpose.	
 
-Initialize the logs in your startup code. It may look like this 
+
+###Configuring Logging for Packages that an Application Uses
+Here is an example of how an application can set the log handlers for the logs of the packages that the application includes.  
+
+In this example, the `package1` package defines the variable  `package1_log` of type `struct log` and externs the variable. Similarly, the `package2` package defines the variable `package2_log` and externs the variable.  The application sets logs for `package1` to use console and sets logs  for `package2` to use a circular buffer.
 
 ```c
-#include <module1/module1.h>
-#include <module3/module2.h>
-#include <module3/module3.h>
+#include <package1/package1.h>
+#include <package2/package2.h>
+#include <util/cbmem.h>
+
 #include <log/log.h>
 
-/* log to console */
-static struct log_handler app_log_handler;
+static uint32_t cbmem_buf[MAX_CBMEM_BUF];
+static struct cbmem cbmem;
+
 
-/* this has to be after all the modules are 
- * initialized and have registered
- * their log modules */
 void app_log_init(void)
 {
 
-    /* create a log handler for all logs . FOr this application
-    ** send them directly to the console port */
-    log_console_handler_init(&app_log_handler);
-    ...
-    /* set up logging for the modules appropriately */
-    module1_log.log_level = LOG_LEVEL_WARN;
-    module2_log.log_level = LOG_LEVEL_INFO;
-    module3_log.log_level = LOG_LEVEL_DEBUG;
-
-    /* set up a single handler for all modules */
-    module1_log.log_handler = &app_log_handler;
-    module2_log.log_handler = &app_log_handler;
-    module3_log.log_handler = &app_log_handler;
+
+   
+    log_register("package1_log", &package1_log, &log_console_handler, NULL, LOG_SYSLEVEL);
+
+    cbmem_init(&cbmem, cbmem_buf, MAX_CBMEM_BUF);
+    log_register("package2_log", &package2_log, &log_cbmem_handler, &cbmem, LOG_SYSLEVEL);
+
 }
 ```
 
 <br>
 
-### Typical use of Logging when writing a module 
-
-When creating a package using its own logging, you can have this type of
-structure.  
+### Implementing a Package that Uses Logging
+This example shows how a package logs to console.  The package registers default logging properties to use the console, but allows an application to override the values. It defines the `my_package_log` variable and makes it external so an application can override log handler.
 
+Make the `my_package_log` variable external:
 ```c
 /* my_package.h*/
 
 /* pick a unique name here */
-extern struct log my_log;
+extern struct log my_package_log;
 ```
 
 <br>
 
-with an implementation in your module that looks like this: 
+Define the `my_package_log` variable and register the console log handler: 
 
 ```c
-
 /* my_package.c */
 
-struct log_handler log_console_handler;
-struct log my_log;
+struct log my_package_log;
 
 {
     ...
-    /* create a default handler for this log stream */
-    log_console_handler_init(&log_console_handler);
 
     /* register my log with a name to the system */
-    log_register("log", &my_log, &log_console_handler);
-
-    /* set up default log level for my package */
-    my_log.log_level = LOG_LEVEL_DEBUG;
+    log_register("log", &my_package_log, &log_console_handler, NULL, LOG_LEVEL_DEBUG);
 
-    LOG_DEBUG(&my_log, LOG_MODULE_DEFAULT, "bla");
-    LOG_DEBUG(&my_log, LOG_MODULE_DEFAULT, "bab");
+    LOG_DEBUG(&my_package_log, LOG_MODULE_DEFAULT, "bla");
+    LOG_DEBUG(&my_package_log, LOG_MODULE_DEFAULT, "bab");
 }
 ```
 
+###Log API and Log Levels
+For more information on the `log` API and log levels, see the `sys/log/full/include/log/log.h` header file.
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/19e0f48f/docs/os/tutorials/pics/task_lesson.png
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/pics/task_lesson.png b/docs/os/tutorials/pics/task_lesson.png
index 0ecb5e8..c10603f 100644
Binary files a/docs/os/tutorials/pics/task_lesson.png and b/docs/os/tutorials/pics/task_lesson.png differ

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/19e0f48f/docs/os/tutorials/tasks_lesson.md
----------------------------------------------------------------------
diff --git a/docs/os/tutorials/tasks_lesson.md b/docs/os/tutorials/tasks_lesson.md
index 39ff6ab..c107395 100644
--- a/docs/os/tutorials/tasks_lesson.md
+++ b/docs/os/tutorials/tasks_lesson.md
@@ -1,5 +1,5 @@
 
-#Core OS Lesson: Tasks and Priority Management
+#Tasks and Priority Management
 **Target Platform: Arduino M0 Pro** (or legacy Arduino Zero or Zero Pro, but not Arduino M0)
 
 This lesson is designed to teach core OS concepts and strategies encountered when 
@@ -21,12 +21,19 @@ You will need the following equipment:
 -   USB to Micro USB Cable
 
 ##Build Your Application
-To save time, we will simply modify the Blinky app. We'll add the Task Management code to
-the Blinky app. Follow the [*Arduino Zero Blinky tutorial*](http://mynewt.apache.org/os/tutorials/arduino_zero/) 
+To save time, we will simply modify the Blinky application. We'll add the Task Management code to
+the Blinky application. Follow the [*Arduino Zero Blinky tutorial*](http://mynewt.apache.org/os/tutorials/arduino_zero/) 
 to create a new project and build your bootloader and application. Finally, build and 
 load the application to your Arduino to verify that everything is in order. Now let\u2019s get started!
 
+##Default Main Task
+During Mynewt system startup, Mynewt creates a default main task and executes the application `main()` function in the context of this task.  The main task priority defaults to 127 and can be configured with the `OS_MAIN_TASK_PRIO` system configuration setting.
+
+
+The blinky application only has the `main` task.  The `main()` function executes an infinite loop that toggles the led and sleeps for one second. 
+<br>
 ##Create a New Task
+
 The purpose of this section is to give an introduction to the important aspects of tasks 
 and how to properly initialize them. First, let\u2019s define a second task called `work_task` 
 in main.c (located in apps/blinky/src):
@@ -44,7 +51,7 @@ Next, let\u2019s take a look at what is required to initialize our new task.
 ### Task Stack
 The task stack is an array of type `os_stack_t` which holds the program stack frames. Mynewt gives 
 us the ability to set the stack size for a task giving the application developer room to optimize 
-memory usage. Since we\u2019re not short on memory, our `blinky_stack` and `work_stack` are plenty large 
+memory usage. Since we\u2019re not short on memory, our `work_stack` is plenty large 
 for the purpose of this lesson. Notice that the elements in our task stack are of type `os_stack_t` 
 which are generally 32 bits, making our entire stack 1024 Bytes.
 
@@ -56,10 +63,8 @@ which are generally 32 bits, making our entire stack 1024 Bytes.
 Note: The `OS_STACK_ALIGN` macro is used to align the stack based on the hardware architecture.
 
 ### Task Function
-The task function is essentially an infinite loop which waits for some \u201cevent\u201d to wake it up. In our 
-Blinky app the task function, named `blinky_task_handler()`, is initially called when we call `os_start()` 
-in `main()`. In general, the task function is where the majority of work is done by a task. Let\u2019s write 
-a task function for `work_task` called `work_task_handler()`:
+
+A task function is essentially an infinite loop that waits for some \u201cevent\u201d to wake it up.  In general, the task function is where the majority of work is done by a task.  Let\u2019s write a task function for `work_task` called `work_task_handler()`:
 
 ```c
 void
@@ -95,8 +100,9 @@ Let\u2019s set the priority of `work_task` to 0, because everyone knows that work i
 
 ### Initialization
 To initialize a new task we use [*os_task_init()*](http://mynewt.apache.org/os/core_os/task/os_task_init/) 
-which takes a number of arguments including our new task function, stack, and priority. Much like `blinky_task`, 
-we\u2019re going to initialize `work_task` inside `init_tasks` to keep our main function clean. We'll set the task stack here and pass it to the `os_task_init()` function as well.
+which takes a number of arguments including our new task function, stack, and priority. 
+
+Add the `init_tasks()` function to initialize `work_task` to keep our main function clean. 
 
 ```c
 int
@@ -106,23 +112,44 @@ init_tasks(void)
     os_stack_t *work_stack;
     work_stack = malloc(sizeof(os_stack_t)*WORK_STACK_SIZE);
     
-    assert(pstack);
+    assert(work_stack);
     os_task_init(&work_task, "work", work_task_handler, NULL,
             WORK_TASK_PRIO, OS_WAIT_FOREVER, work_stack,
             WORK_STACK_SIZE);
 
-    tasks_initialized = 1;
     return 0;
 }
 ```
+<br>
+
+Add the call to `init_tasks()` in `main()` before the `while` loop:
+
+```c
+
+int
+main(int argc, char **argv)
+{
+
+        ...
+
+    /* Initialize the work task */
+    init_tasks();
+
+    while (1) {
+         ...
+    }
+}
+```
 
+<br>
 And that\u2019s it! Now run your application using the newt run command.
 ```
 $ newt run arduino_blinky 0.0.0
 ```
+<br>
 When GDB appears press C then Enter to continue and \u2026 *wait, why doesn't our LED blink anymore?*
 
-
+<br>
 #### Review
 Before we run our new app, let\u2019s review what we need in order to create a task. This is a general case for a new task called mytask:
 
@@ -146,7 +173,7 @@ mytask_handler(void *arg)
   }
 }
 ```
-**3)** Initialize task before calling `os_start()`:
+**3)** Initialize the task:
 ```c
 os_task_init(&mytask, "mytask", mytask_handler, NULL, 
             MYTASK_PRIO, OS_WAIT_FOREVER, mytask_stack,
@@ -160,11 +187,9 @@ place of) the lower priority task which is *running*. When a lower priority task
 priority task, the lower priority task\u2019s context data (stack pointer, registers, etc.) is saved and the new 
 task is switched in.
 
-In our example, `work_task` has a higher priority than `blinky_task` and, because it is never put into a 
-*sleep* state, holds the processor focus on its context. Let\u2019s give `work_task` a delay and some simulated 
-work to keep it busy. Because the delay is measured in os ticks, the actual number of ticks per second is 
-dependent on the board. Therefore, we multiply `OS_TICKS_PER_SEC`, which is defined in the MCU, by the 
-number of seconds we wish to delay.
+In our example, `work_task` (priority 0) has a higher priority than the `main` task (priority 127).  Since `work_task` is never put into a *sleep* state, it holds the processor focus on its context. 
+
+Let\u2019s give `work_task` a delay and some simulated work to keep it busy. The delay is measured in os ticks and the actual number of ticks per second is dependent on the board. We multiply `OS_TICKS_PER_SEC`, which is defined in the MCU, by the number of seconds we wish to delay.
 
 ```c
 void
@@ -182,24 +207,25 @@ work_task_handler(void *arg)
         int i;
         for(i = 0; i < 1000000; ++i) {
             /* Simulate doing a noticeable amount of work */
-            hal_gpio_set(g_led_pin);
+            hal_gpio_write(g_led_pin, 1);
         }
-        os_time_delay(3*OS_TICKS_PER_SECOND);
+        os_time_delay(3 * OS_TICKS_PER_SEC);
     }
 }
 ```
+<br>
+In order to notice the LED changing, modify the time delay in `main()` to blink at a higher frequency.
 
-In order to notice the LED changing, modify the time delay in `blinky_task_handler()` to blink at a higher frequency.
 ```c
 os_time_delay(OS_TICKS_PER_SEC/10);
 ```
+<br>
 Before we run the app, let\u2019s predict the behavior. With the newest additions to `work_task_handler()`, 
-our first action will be to sleep for three seconds. This will allow `blinky_task` to take over the CPU 
-and blink to its heart\u2019s content. After three seconds, `work_task` will wake up and be made *ready to run*, 
-causing it to preempt `blinky_task`. The LED will then remain lit for a short period while `work_task` 
+our first action will be to sleep for three seconds. This allows the `main` task, running `main()`, to take over the CPU and blink to its heart\u2019s content. After three seconds, `work_task` will wake up and be made *ready to run*. 
+This causes it to preempt the `main` task. The LED will then remain lit for a short period while `work_task` 
 loops, then blink again for another three seconds while `work_task` sleeps. 
 
-Voila, you should see that our prediction was correct! 
+You should see that our prediction was correct! 
 
 
 ###Priority Management Considerations
@@ -211,198 +237,11 @@ Some tasks, such as the Shell task, execute quickly and require almost instantan
 the Shell task should be given a high priority. On the other hand, tasks which may be communicating over 
 a network, or processing data, should be given a low priority in order to not hog the CPU.
 
-The diagram below showcases the different scheduling patterns we. would expect from swapping blinky and 
-work tasks priorities.
+The diagram below shows the different scheduling patterns we would expect when we set the `work_task` priority higher and lower than the `main` task priority.  
 
-![Task Scheduling](pics/task_lesson.png)
+![Task Scheduling](pics/task_lesson1.png)
 
-In the second case where `blinky_task` has a higher priority, the \u201cwork\u201d done by `work_task` would be 
-executed during the millisecond delays in `blinky_task`, saving us idle time compared to the first case.
+In the second case where the `main` task has a higher priority, `work_task` runs and executes \u201cwork\u201d when
+the `main` task sleeps, saving us idle time compared to the first case.
 
 **Note:** Defining the same priority for two tasks leads to somewhat undefined behavior and should be avoided.
-
-##Comparing Priority Strategies
-
-Instead of stepping through a bunch of changes to our blinky app, clone my task lesson application from 
-github and copy an existing target.
-
-Change directory into apps and clone the repository to get our new
-files:
-```
-$ cd apps
-$ git clone https://github.com/bgiori/mynewt_tasks_lesson.git
-```
-Change directory back to your project root and copy  the arduino_blinky target to a new target called task_tgt.
-```c
-$ newt target copy arduino_blinky task_tgt
-```
-Set a new app location.
-```c
-$ newt target set task_tgt app=apps/mynewt_tasks_lesson
-```
-
-Now let\u2019s take a look at our new code. First, notice that we have abandoned blinking, instead 
-choosing to use the [*console*](http://mynewt.apache.org/latest/os/modules/console/console/) 
-and [*shell*](http://mynewt.apache.org/latest/os/modules/shell/shell/) to follow our tasks through execution.
-
-Additionally, we have a number of different tasks:
-
--   **Task A** (`a_task`):
-    -   **Priority**: 3 \u2192 2
-    -   **Description**: Task A is supposed to represent a task which frequently does a small amount 
-    of work, such as one which rapidly polls a sensor for data. Much like `blinky_task`, Task A will 
-    loop 10,000 times then wait 1 millisecond. Priority is changed by `timer_task` after the first simulation.
-
--   **Task B** (`b_task`):
-    -   **Priority**: 2 \u2192 3
-    -   **Description**: Task B is supposed to represent a task which does a large amount of work 
-    relatively infrequently, such as one which sends/receives data from the cloud. Like work\_task, 
-    Task B will loop 1,000,000 times then wait 3 seconds. Priority is changed by timer\_task after 
-    the first simulation.
-
--   **Timer Task** (`timer_task`):
-    -   **Priority**: 1
-    -   **Description**: With default settings, Timer Task will wait 20 seconds then print the first 
-    simulations data for Task A and B. Timer task will then swap A and B\u2019s priorities and restart the 
-    simulation. After the second simulation, timer will again print simulation data then compare the 
-    two and calculate a final speedup (simulation2 / simulation1).
-
-- **Shell Task**:
-    -   **Priority**: 0
-    -   **Description**: Task used by Shell behind the scenes to communicate with the serial port.
-
-### Connecting to the Serial Console
-
-Before running our new app, we must first connect to the serial console. First make sure the 
-mynewt_arduino_zero repository is set to the develop branch. (Remove once changes have been 
-moved to master). 
-```
-$ cd repos/mynewt_arduino_zero
-$ git checkout develop
-```
-
-You should already be familiar with the [Serial Port Setup and Configuration](../get_started/serial_access.md), but if
-you're not, you can go there now and then come back. 
-
-### Output Analysis
-
-Run our new target, task_tgt, and you should see an output similar to this:
-
-```
-Starting First Simulation...
-1:     Task B: 0% 
-78:     Task B: 1% 
-155:     Task B: 2% 
-257:     Task B: 3% 
-359:     Task B: 4% 
-461:     Task B: 5% 
-
-<snip>
-
-========== Timer Expired ==========
-
- >>> Task A <<<
-  Priority: 3
-  Loop count: 162849
-  Cycle count: 16.28
-  Run time: 1.40 sec
-
- >>> Task B <<<
-  Priority: 2
-  Loop count: 1345852
-  Cycle count: 1.34
-  Run time: 17.0 sec
-
- Total loops: 1508709
-
-20023:   Switching priorities and restarting...
-20111:   Task A looped
-20113:     Task B: 0% 
-20191:     Task B: 1% 
-20297:   Task A looped
-20356:     Task B: 2% 
-20483:   Task A looped
-20545:     Task B: 3% 
-20669:   Task A looped
-20734:     Task B: 4% 
-20855:   Task A looped
-20923:     Task B: 5% 
-
-<snip>
-
-========== Timer Expired ==========
-
- >>> Task A <<<
-  Priority: 2
-  Loop count: 1080000
-  Cycle count: 108.0
-  Run time: 9.28 sec
-
- >>> Task B <<<
-  Priority: 3
-  Loop count: 830356
-  Cycle count: 0.83
-  Run time: 10.72 sec
-
- Total loops: 1910404
-
-40058:
-
- Final Speedup (Sim2 / Sim1): 1.26
-
-```
-
-The console output reaffirms our previous prediction and makes both the scheduling differences 
-and subsequent efficiency boost far more apparent. Let\u2019s take a look at scheduling differences 
-before we delve into efficiency.
-
-In the first case, where Task B\u2019s priority is higher than that of Task A, we see A get starved 
-by Task B\u2019s long execution time. **Starvation** occurs when one task hogs the processor, essentially 
-\u201cstarving\u201d other tasks which also need to run. At the end of the first 20 second simulation period, 
-Task A has only run for 1.4 seconds compared to task B\u2019s 17 second running time \u2013 ouch. As explained 
-before, processes which are expected to run for long periods of time (e.g. network communication, 
-data processing) should be given higher priorities in order to combat starvation.
-
-In the second simulation with priorities swapped, we can see Task B only running during the 
-millisecond delays when Task A is *sleeping*. Although having Task B only run during these 
-delays slows its execution time, we benefit from un-starving Task A and using the processor 
-at a higher efficiency.
-
-The bottom line speedup gives us an immediate and clear indication that we have improved our 
-ability to process work (i.e throughput). In our second run, we processed an additional 400,000 
-loop iterations, equating to a 26% increase in efficiency. On a standard multi-core processor 
-found in every modern PC, a 1.26 speedup would be an ok result to adding multithreading capabilities 
-to a serial program. However, we accomplished this by simply setting priorities on a single core 
-processor \u2013 not bad!
-
-NOTE: Usually the the term \u201cspeedup\u201d is used within a parallel programming context and refers 
-to the change in execution time between a serial and parallel program executing over the same 
-problem. In this case we\u2019re using the term loosely to illustrate the priority change\u2019s effect 
-on scheduling and throughput in our specific context.
-
-### Efficiency Isn\u2019t Everything
-
-Using the processor during every OS tick isn\u2019t always the best course of action. If we modify 
-Task A\u2019s delay to a tenth of a millisecond and turn off the console output, we can boost our 
-speedup to 1.44. This, however, reduces our ability to process work from Task B who ends up 
-only completing 18% of its work cycle after the second simulation. That would mean, at that 
-rate, Task B would take over a minute to finish one cycle.
-
-Feel free to play around with the testing parameters to study the different changes yourself!
-
-###Conclusion
-
-Moving forward, tasks are just the tip of the iceberg. The [*scheduler*](http://mynewt.apache.org/latest/os/core_os/context_switch/context_switch/), 
-[*event queues*](http://mynewt.apache.org/latest/os/core_os/event_queue/event_queue/), 
-[*semaphores*](http://mynewt.apache.org/latest/os/core_os/semaphore/semaphore/), and 
-[*mutexes*](http://mynewt.apache.org/latest/os/core_os/mutex/mutex/) also add to tasks functionality, 
-increasing our ability as the developer to control greater numbers of tasks more intricately. For 
-example, when we switch the tasks priority, we have to tell the scheduler that our tasks priorities 
-have changed, allowing us us to use priorities dynamically. When running multiple tasks, logging 
-through either the built-in [*Logs*](http://mynewt.apache.org/latest/os/modules/logs/logs/) module 
-(not covered in this lesson) or through the serial console/shell can be very useful for debugging 
-your application. In the end, the way you manage your tasks depends on the context of your 
-application. You should assign priorities based on execution time, urgency, and frequency, among 
-other things.
-
-Keep blinking and happy hacking!