Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions tutorials/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Tutorials

This folder contains tutorials introducing Highway. The
tutorials are in Jupyter notebooks. They can be run on
your own machine, but can also be run through a web browser
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can add mention on how to run these locally?

on [Google Colab](https://colab.research.google.com) or on
[MyBinder](https://mybinder.org/) or other cloud services that
allow one to execute Jupyter Notebooks.

- Vector Add
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/google/highway/tutorials/vector_add.ipynb)
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/google/highway/tutorials/vector_add.ipnyb/HEAD)
328 changes: 328 additions & 0 deletions tutorials/vector_add.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,328 @@
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
}
},
"cells": [
{
"cell_type": "markdown",
"source": [
"Copyright 2026 Google LLC\n",
"SPDX-License-Identifier: Apache-2.0\n",
"\n",
"Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"you may not use this file except in compliance with the License.\n",
"You may obtain a copy of the License at\n",
"\n",
" http://www.apache.org/licenses/LICENSE-2.0\n",
"\n",
"Unless required by applicable law or agreed to in writing, software\n",
"distributed under the License is distributed on an \"AS IS\" BASIS,\n",
"WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"See the License for the specific language governing permissions and\n",
"limitations under the License"
],
"metadata": {
"id": "YNknTdrHd024"
}
},
{
"cell_type": "markdown",
"source": [
"First setup an environment to enable one to learn how to use Highway."
],
"metadata": {
"id": "Si4d423YTtoJ"
}
},
{
"cell_type": "code",
"source": [
"!apt update -qq;\n",
"!apt-get update -qq;\n",
"!apt update\n",
"!apt install cmake gcc g++ git libatomic1 libgtest-dev ninja-build\n",
"!apt-get upgrade"
],
"metadata": {
"id": "mZAXwNtqT6Pu"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Now get the highway code and install Highway. This may take about 10 minutes. To not extend build time further, do not build tests and examples."
],
"metadata": {
"id": "DvphHZwhVSA5"
}
},
{
"cell_type": "code",
"source": [
"#!git clone https://github.com/google/highway\n",
"%cd highway\n",
"!mkdir build\n",
"%cd build\n",
"!cmake -GNinja \\\n",
" -DHWY_ENABLE_TESTS=OFF \\\n",
" -DHWY_ENABLE_EXAMPLES=OFF \\\n",
" -DHWY_ENABLE_CONTRIB=ON \\\n",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we disable CONTRIB to speed up the build?

Also, if we were to build PPAs, how would those be referenced from the install step here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disabling CONTRIB can help. It may be helpful to give a choice of building or installing a PPA. Going through the steps of building can be helpful for someone to build on their own machine.

Checking on PPAs at https://documentation.ubuntu.com/launchpad/user/reference/packaging/ppas/ppa/
There is an action that will help with this https://github.com/marketplace/actions/publish-ppa-package

Some people also use org-mode to create notebooks:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, agree it would be nice to set ENABLE_CONTRIB=OFF here :)

Nice find with the PPA action! Would you like to send a separate PR adding that workflow for manual dispatch (by adding a workflow_dispatch section)? I'd be willing to run this after releases.

" -DCMAKE_INSTALL_PREFIX=/content/highway_install ..\n",
"!ninja\n",
"!ninja install\n",
"%cd ..\n",
"%cd .."
],
"metadata": {
"id": "XJGOuRrHVX61"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [],
"metadata": {
"id": "TmL-d260daxu"
}
},
{
"cell_type": "markdown",
"source": [
"As a first example, let us try out a program to do a vector addition."
],
"metadata": {
"id": "I4JbTFcUeHrH"
}
},
{
"cell_type": "code",
"source": [
"%%writefile vector_add.cpp\n",
"#include <stddef.h>\n",
"#include <stdint.h>\n",
"\n",
"#include <chrono>\n",
"#include <iostream>\n",
"#include <numeric>\n",
"#include <vector>\n",
"\n",
"float SumArray(const float* array, size_t count) {\n",
" float sum = 0;\n",
" for (size_t i = 0 ; i < count; i++) {\n",
" sum += array[i];\n",
" }\n",
" return sum;\n",
"}\n",
"\n",
"int main() {\n",
" const size_t count = 1025;\n",
" std::vector<float> data(count);\n",
" std::iota(data.begin(), data.end(), 1.0f);\n",
" //start timer\n",
" auto start = std::chrono::high_resolution_clock::now();\n",
" float sum = SumArray(data.data(), count);\n",
" //stop timer and print time and sum\n",
" auto stop = std::chrono::high_resolution_clock::now();\n",
" std::chrono::duration<double, std::milli> diff = stop - start;\n",
" std::cout << \"Execution time: \" << diff.count() << \" ms\" << std::endl;\n",
" std::cout << \"Sum: \" << sum << std::endl;\n",
"\n",
" return 0;\n",
"}"
],
"metadata": {
"id": "eEuRa_9Qe29p"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Now compile and run this program with no optimization."
],
"metadata": {
"id": "FUsIWK5nggb8"
}
},
{
"cell_type": "code",
"source": [
"!g++ -std=c++17 -O0 -o vector_add.o -c vector_add.cpp\n",
"!g++ -o vectoradd vector_add.o\n",
"!./vector_add"
],
"metadata": {
"id": "y4V99UFfgpau"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Now compile and run an optimized executable."
],
"metadata": {
"id": "tsRbfP4Hi4SJ"
}
},
{
"cell_type": "code",
"source": [
"!g++ -O3 vector_add.cpp -o vector_add\n",
"!./vector_add"
],
"metadata": {
"id": "k5DgYSprip_0"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Now use Highway to do explicit vectorization."
],
"metadata": {
"id": "QhhDEzBsjdjj"
}
},
{
"cell_type": "code",
"source": [
"%%writefile vector_add_hwy.cpp\n",
"#include <stddef.h>\n",
"#include <stdint.h>\n",
"\n",
"#include <chrono>\n",
"#include <iostream>\n",
"#include <numeric>\n",
"#include <vector>\n",
"\n",
"\n",
"// >>>> for dynamic dispatch only, skip if you want static dispatch\n",
"\n",
"// First undef to prevent error when re-included.\n",
"#undef HWY_TARGET_INCLUDE\n",
"// For dynamic dispatch, specify the name of the current file (unfortunately\n",
"// __FILE__ is not reliable) so that foreach_target.h can re-include it.\n",
"// The absolute path seems to be required\n",
"#define HWY_TARGET_INCLUDE \"/content/vector_add_hwy.cpp\"\n",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good practice to avoid absolute paths in includes. Just "vector_add_hwy"?

"// Generates code for each enabled target by re-including this source file.\n",
"#include \"hwy/foreach_target.h\" // IWYU pragma: keep\n",
"\n",
"// <<<< end of dynamic dispatch\n",
"//\n",
"#include \"hwy/highway.h\"\n",
"\n",
"HWY_BEFORE_NAMESPACE();\n",
"namespace hwy {\n",
"namespace HWY_NAMESPACE {\n",
"namespace hn = hwy::HWY_NAMESPACE;\n",
"\n",
"float SumArraySIMD(const float* HWY_RESTRICT array, size_t count) {\n",
" const hn::ScalableTag<float> d;\n",
" using V = hn::Vec<decltype(d)>;\n",
" V sum = hn::Zero(d);\n",
" size_t i = 0;\n",
" const size_t N = hn::Lanes(d);\n",
" if (count >= N) {\n",
" for (; i <= count - N; i += N) {\n",
" sum = hn::Add(sum, hn::LoadU(d, array + i));\n",
" }\n",
" }\n",
" float total = hn::ReduceSum(d, sum);\n",
" // Simple scalar remainder handling\n",
" for (; i < count; ++i) {\n",
" total += array[i];\n",
" }\n",
" return total;\n",
"}\n",
"\n",
"} // namespace HWY_NAMESPACE\n",
"} // namespace hwy\n",
"HWY_AFTER_NAMESPACE();\n",
"\n",
"#if HWY_ONCE\n",
"namespace hwy {\n",
"HWY_EXPORT(SumArraySIMD);\n",
"\n",
"float CallSumArraySIMD(const float* array, size_t count) {\n",
" return HWY_DYNAMIC_DISPATCH(SumArraySIMD)(array, count);\n",
"}\n",
"\n",
"} // namespace hwy\n",
"\n",
"int main() {\n",
" const size_t count = 1025;\n",
" std::vector<float> data(count);\n",
" std::iota(data.begin(), data.end(), 1.0f);\n",
" //start timer\n",
" auto start = std::chrono::high_resolution_clock::now();\n",
" float sum = hwy::CallSumArraySIMD(data.data(), count);\n",
" //stop timer and print time and sum\n",
" auto stop = std::chrono::high_resolution_clock::now();\n",
" std::chrono::duration<double, std::milli> diff = stop - start;\n",
" std::cout << \"Execution time: \" << diff.count() << \" ms\" << std::endl;\n",
" std::cout << \"Sum: \" << sum << std::endl;\n",
"\n",
" return 0;\n",
"}\n",
"#endif // HWY_ONCE"
],
"metadata": {
"id": "ANEqe3CtkMTj"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Compile and run explicitly vectorized version."
],
"metadata": {
"id": "TfsXskkcluH1"
}
},
{
"cell_type": "code",
"source": [
"!g++ -std=c++17 -O3 -I/content/highway_install/include -o vector_add_hwy.o -c vector_add_hwy.cpp\n",
"!g++ -o vector_add_hwy vector_add_hwy.o -L/content/highway_install/lib -lhwy_contrib -lhwy\n",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add -I/ for the above.

"!./vector_add_hwy"
],
"metadata": {
"id": "_f93Lxefly6n"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"Try increasing the array size, then recompile and run the examples again. For what array size is the explicitly SIMD vectorized program faster than the program with O0 optimization? What about for O3 optimization?\n",
"\n",
"Ideally, make a plot showing execution time against array size for the program with O0 optimization, O3 optimization and explicitly vectorized using Highway."
],
"metadata": {
"id": "JSd31IBzA1L6"
}
}
]
}
Loading