January 25, 2024

MojošŸ”„ SDK v0.7 now available for download!

Mojo SDK v0.7 is the first big release of MojošŸ”„ in 2024, and itā€™s chock full of new language and standard library feature goodness. In this blog post, Iā€™ll share some of the key highlights from this release with examples, and discuss what they are and when to use them. Iā€™m only going to cover the new features, for a complete list of whatā€™s new, whatā€™s changed, whatā€™s removed, and whatā€™s fixed in this release, be sure to check out the changelog in the Mojo documentation.

First things first: Update your modular CLI and MojošŸ”„ SDK

Before we take a closer look at the new features, make sure you update the modular CLI and mojo. First, head over to the developer console and follow the platform-specific instructions to upgrade your modular CLI to version 0.4.1. The latest version of the modular CLI includes performance improvements and a brand-new progress bar!

Once youā€™ve updated your modular CLI, run modular update mojo to get the latest v0.7 release of Mojo SDK.

Whatā€™s New in Mojo SDK v0.7?

This release includes exciting new features across the core language, the standard library, and developer tools. Iā€™ll highlight the key features in this release categorized into two areas:

  • Mojo language and standard library features
  • Mojo CLI and language server features

New Mojo language and standard library features

Mojo-native dictionary type

This release introduces a new Mojo-native dictionary type! Dictionaries are really useful dynamic and mutable data structures for storing key-value data. If you are a Python data science developer, youā€™ve probably used dictionaries to store model configurations, model architectures, hyperparameters or to read entire JSON files. Letā€™s take a look at the Mojo dictionary type with a simple example.

Mojo
from collections.dict import Dict, KeyElement @value struct StringKey(KeyElement): var s: String fn __init__(inout self, owned s: String): self.s = s ^ fn __init__(inout self, s: StringLiteral): self.s = String(s) fn __hash__(self) -> Int: return hash(self.s) fn __eq__(self, other: Self) -> Bool: return self.s == other.s fn main() raises: var hyperparam = Dict[StringKey, Float64]() hyperparam["learning_rate"] = 0.01 hyperparam["weight_decay"] = 1e-6 hyperparam["momentum"] = 0.90 print('Dict size: ',len(hyperparam)) print('Learning rate: ',hyperparam["learning_rate"]) print('Momentum: ', hyperparam["momentum"]) print(hyperparam.pop("momentum")) print(len(hyperparam))

In the above code example, we created a simple Mojo dictionary called hyperparam to store a modelā€™s hyperparameters learning_rate, weight_decay, and momentum as key-value pairs. You can query an element just like how youā€™d do it with Python, by calling dict_variable[ā€˜key_nameā€™]. To remove an element from the dictionary, use the pop function.

If you pay close attention to the dictionary creation code, youā€™ll see that we use StringKey and not the standard library String type. Dictionary keys need to conform to the new KeyElement trait, which is not yet implemented by other standard library types like String in this release. They will be implemented in a future release, but for now, youā€™ll need to create custom wrappers around the value type that implements the KeyElement trait.

New functions to get host CPUā€™s physical, logical and performance core counts

If you want to write portable parallelizable code, itā€™s useful to be able to programmatically access the number of cores on the host CPU. However, modern CPUs may implement a hybrid performance+efficiency core CPU architecture or include logical cores, and choosing the wrong number of threads in code may hurt your parallel applicationā€™s performance. In this release, sys.info includes 3 new functions that let you programmatically access the number of physical cores, number of logical cores and, number of high-performance cores.

Mojo
from sys.info import num_physical_cores, num_logical_cores, num_performance_cores fn main(): print('Number of physical cores:',num_physical_cores()) print('Number of logical cores:',num_logical_cores()) print('Number of performance cores:', num_performance_cores())

On My Apple MacBook Pro M2 Max system running the above code shows that I have 8 performance cores even though I have 12 physical cores.

Output
Number of physical cores: 12 Number of logical cores: 12 Number of performance cores: 8

On an Amazon EC2 c6i.4xlarge instance, see that although there are no efficiency cores, it does support logical cores with Intelā€™s Hyper-ThreadingĀ 

Output
Number of physical cores: 8 Number of logical cores: 16 Number of performance cores: 8

New safe References type (prototype)

In this release, Mojo also introduces a prototype version of a Reference, a safe alternative to unsafe pointers. References have the same in-memory representation as Mojo pointers but also track a ā€œlifetimeā€ value so the compiler can reason about a potentially accessed set of values. While this is a major step forward for the lifetimes system in Mojo, it is a very early prototype implementation. Read more about references in the changelog and the Reference documentation.

New Mojo CLI and language server features

New compiler option to opt-in debug assertions used in standard library functions

Mojo standard library functions include several assertions to catch various errors but are not enabled by default to improve performance. Letā€™s take a look at a simple example.

Mojo
from sys.info import simdwidthof, simdbitwidth alias simd_width: Int = simdwidthof[DType.float32]() fn main(): print("SIMD Width:",simd_width) let a = SIMD[DType.float32](1,2,3,4,5,6) print(a)

If you compile and run this code, youā€™ll see the following output:

Output
mojo mojo_stdlib_assert.mojo SIMD Width: 4 [1.0, 2.0, 3.0, 4.0]

Everything looks good, and it works as expected. If you look closely at the code, we initialized the SIMD type with 6 values, but the SIMD width for Float32 is only 4. But SIMD did the right thing and truncated values > 4. The SIMD implementation in the standard library includes a check to see if the number of input values is larger than the SIMD width, but since these assertions are disabled by default, you only see a truncated output. To enable the assertions, you can now opt-in by specifying -D MOJO_ENABLE_ASSERTIONS when calling the mojo compiler.

If you compile and run this code with the flag, you get an Assert Error and the stack trace. This new feature be useful for debugging if youā€™re seeing unexpected results.

Bash
mojo -D MOJO_ENABLE_ASSERTIONS mojo_stdlib_assert.mojo SIMD Width: 4 Assert Error: mismatch in the number of elements Please submit a bug report to https://github.com/modularml/mojo/issues and include the crash backtrace along with all the relevant source codes. Stack dump: 0. Program arguments: mojo -D MOJO_ENABLE_ASSERTIONS mojo_stdlib_assert.mojo Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it): 0 mojo 0x0000000100c9a65c llvm_strlcpy + 52684 1 mojo 0x0000000100c987bc llvm_strlcpy + 44844 2 mojo 0x0000000100c9acfc llvm_strlcpy + 54380 3 libsystem_platform.dylib 0x0000000188af5a24 _sigtramp + 56 4 libsystem_platform.dylib 0xffff80028000428c _sigtramp + 18446603340370471072 5 mojo 0x0000000101070728 llvm_strlcpy + 4075160 6 mojo 0x0000000100bf2cf0 7 mojo 0x0000000100bdd114 8 dyld 0x00000001887450e0 start + 2360 [51137:14139255:20240125,031201.678546:WARNING in_range_cast.h:38] value -634136515 out of range [51137:14139255:20240125,031201.682782:WARNING crash_report_exception_handler.cc:257] UniversalExceptionRaise: (os/kern) failure (5) Trace/BPT trap: 5

New Find All References and Go to References feature support in Visual Studio Code IDE

We discussed some exciting new features in the core language and standard library, but weā€™re not done yet. The Mojo Language Server also gets new superpowers! The language server now implements the References request. IDEs like Visual Studio Code can use this to provide support for Go to References and Find All References. Currently, references are limited to a single open document, cross-document references will be supported in a future release.

But wait, there is more!

We discussed key highlights in this release, but thereā€™s more! This release also includes changes and enhancements to closures, unroll, vectorize and a host of bug fixes. Check out the changelog for a full list of whatā€™s new, whatā€™s changed, and bug fixes in this release:

Download Mojo SDK v0.7 today! Here are other useful getting started and community resources:

Until next time! šŸ”„

Shashank Prasanna
,
AI Developer Advocate

Shashank Prasanna

AI Developer Advocate

Shashank is an engineer, educator and doodler. He writes and talks about machine learning, specialized machine learning hardware (AI Accelerators) and AI Infrastructure in the cloud. He previously worked at Meta, AWS, NVIDIA, MathWorks (MATLAB) and Oracle in developer relations and marketing, product management, and software development roles and hold an M.S. in electrical engineering.