# Record
**Author:** @cameron.stream (`did:plc:gfrmhdmjvxn2sjedzboeudef`)

## `juliacon-2024-workshops`
**Collection:** `site.standard.document`
**AT URI:** `at://did:plc:gfrmhdmjvxn2sjedzboeudef/site.standard.document/juliacon-2024-workshops`

**Title:** JuliaCon 2024 Workshops
**Published:** Tue, 09 Jul 2024 07:00:00 GMT
**Publication:** `at://did:plc:gfrmhdmjvxn2sjedzboeudef/site.standard.publication/3md7ylshxzk2y`
**Path:** /juliacon-2024-workshops
**Tags:** blog

**Content:**
```json
{
  "$type": "pub.leaflet.content",
  "pages": [
    {
      "id": "92d387ce-7121-4161-89fd-30307a38064d",
      "$type": "pub.leaflet.pages.linearDocument",
      "blocks": [
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.header",
            "level": 1,
            "plaintext": "JuliaCon 2024"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "It's workshop day!"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.header",
            "level": 2,
            "plaintext": "Parallel processing with Dagger.jl"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "facets": [
              {
                "index": {
                  "byteEnd": 9,
                  "byteStart": 0
                },
                "features": [
                  {
                    "uri": "https://github.com/JuliaParallel/Dagger.jl",
                    "$type": "pub.leaflet.richtext.facet#link"
                  }
                ]
              }
            ],
            "plaintext": "Dagger.jl is an extremely cool tool. I used Dagger sometime in 2018 I think, but I didn't really have a good distributed computing problem to solve."
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "facets": [
              {
                "index": {
                  "byteEnd": 37,
                  "byteStart": 19
                },
                "features": [
                  {
                    "uri": "https://szufel.pl/",
                    "$type": "pub.leaflet.richtext.facet#link"
                  }
                ]
              },
              {
                "index": {
                  "byteEnd": 91,
                  "byteStart": 73
                },
                "features": [
                  {
                    "uri": "https://github.com/jpsamaroo/DaggerWorkshop2024",
                    "$type": "pub.leaflet.richtext.facet#link"
                  }
                ]
              }
            ],
            "plaintext": "Julian Samaroo and Przemysław Szufel presented the workshop. Here's the workshop materials."
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "facets": [
              {
                "index": {
                  "byteEnd": 45,
                  "byteStart": 32
                },
                "features": [
                  {
                    "$type": "pub.leaflet.richtext.facet#italic"
                  }
                ]
              }
            ],
            "plaintext": "My takeaway was this: Dagger is fucking crazy. Essentially, it unifies a bunch of forms of parallel computation: multithread, multiprocess, and GPU. You provide Dagger a collection of resources (such as threads, worker processes, or GPUs) and it handles the scheduling of tasks on those resources."
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "Dagger will pretty much auto-magically figure out things like memory movement between processes -- for cheap tasks, you want to keep data within-process to minimize memory movement, but in some cases a worker may be overloaded and it may be cheaper to move memory to a different worker."
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "facets": [
              {
                "index": {
                  "byteEnd": 69,
                  "byteStart": 47
                },
                "features": [
                  {
                    "uri": "https://docs.julialang.org/en/v1/base/parallel/",
                    "$type": "pub.leaflet.richtext.facet#link"
                  }
                ]
              }
            ],
            "plaintext": "The simple version of Dagger resembles Julia's standard task workflow:"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.code",
            "language": "julia",
            "plaintext": "t = Dagger.@spawn 1+2\n@show t\nfetch(t)"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "facets": [
              {
                "index": {
                  "byteEnd": 1,
                  "byteStart": 0
                },
                "features": [
                  {
                    "$type": "pub.leaflet.richtext.facet#code"
                  }
                ]
              },
              {
                "index": {
                  "byteEnd": 17,
                  "byteStart": 12
                },
                "features": [
                  {
                    "$type": "pub.leaflet.richtext.facet#code"
                  }
                ]
              },
              {
                "index": {
                  "byteEnd": 96,
                  "byteStart": 88
                },
                "features": [
                  {
                    "$type": "pub.leaflet.richtext.facet#code"
                  }
                ]
              }
            ],
            "plaintext": "t here is a DTask, which represents a task that will execute on some parallel resource. fetch(t) will block and return the result of the task."
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "Dagger will also construct a DAG (hence the name DAGger) of your computation -- you can construct an arbitrary set of tasks, and each task will be handed off to another process upon completion. Take this for example:"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.code",
            "language": "julia",
            "plaintext": "# Multiple dependencies and parallelism\nx = rand(5000)\na = Dagger.@spawn x .+ 1\nb = Dagger.@spawn a .* 2\nc = Dagger.@spawn a ./ 2 # b and c are independent and be run parallel\nd = Dagger.@spawn b .- c\nfetch(d)"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "facets": [
              {
                "index": {
                  "byteEnd": 8,
                  "byteStart": 7
                },
                "features": [
                  {
                    "$type": "pub.leaflet.richtext.facet#code"
                  }
                ]
              },
              {
                "index": {
                  "byteEnd": 14,
                  "byteStart": 13
                },
                "features": [
                  {
                    "$type": "pub.leaflet.richtext.facet#code"
                  }
                ]
              },
              {
                "index": {
                  "byteEnd": 60,
                  "byteStart": 59
                },
                "features": [
                  {
                    "$type": "pub.leaflet.richtext.facet#code"
                  }
                ]
              },
              {
                "index": {
                  "byteEnd": 78,
                  "byteStart": 77
                },
                "features": [
                  {
                    "$type": "pub.leaflet.richtext.facet#code"
                  }
                ]
              },
              {
                "index": {
                  "byteEnd": 84,
                  "byteStart": 83
                },
                "features": [
                  {
                    "$type": "pub.leaflet.richtext.facet#code"
                  }
                ]
              }
            ],
            "plaintext": "Above, b and c are independent and can be run in parallel. d depends on both b and c, so it will block until both are complete."
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "GPU support is quite straightforward as well. Julia's GPU support is wonderful, and you can use any device type you need (CUDA, ROCm, Metal, oneAPI)."
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "Here's how to set up a GPU in Dagger:"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.code",
            "language": "julia",
            "plaintext": "using DaggerGPU\nusing CUDA\n\n# Annoying, but we need to restart the scheduler for the below changes to take effect...\n# Will be fixed in future versions of Dagger!\nDagger.cancel!(;halt_sch=true)\n\n# Make sure that we have at least one GPU\n@assert length(CUDA.devices()) > 0 \"You don't have any NVIDIA GPUs!\"\n\n# Pick the first available GPU\nGPUArray = CuArray\nscope = Dagger.scope(;cuda_gpu=1)"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "facets": [
              {
                "index": {
                  "byteEnd": 23,
                  "byteStart": 18
                },
                "features": [
                  {
                    "$type": "pub.leaflet.richtext.facet#code"
                  }
                ]
              }
            ],
            "plaintext": "Once you have the scope that determines Dagger's available resources (in this case, a GPU), you can let Dagger handle whatever your operation is:"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.code",
            "language": "julia",
            "plaintext": "# Run our `sum` function on the GPU!\nA = rand(Float32, 1024)\nDagger.with_options(;scope) do\n    @show fetch(Dagger.@spawn sum(A))\nend"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "This also handles multiple GPUs across processes. If the GPUs are full or computations are not appropriate for a GPU, they can also be dispatched to a multithreading paradigm."
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "There's lots of other cool stuff in the talk, including data dependencies to help the Dagger scheduler, distributed arrays, and a nifty implementation of convolutions + Conway's Game of Life."
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "Honestly I was just amazed at how far Dagger.jl has come. They have a ton of stuff on the roadmap as well, including"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "• DaggerGraphs.jl for partitioned distributed graph processing"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "• Streaming data"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "• Auto-GPU processing"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "• Expanded data deps support"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "• Operator fusion"
          }
        },
        {
          "$type": "pub.leaflet.pages.linearDocument#block",
          "block": {
            "$type": "pub.leaflet.blocks.text",
            "plaintext": "• Dagger + Enzyme autodiff"
          }
        }
      ]
    }
  ]
}
```

---
*Fetched from https://enoki.us-east.host.bsky.network via `com.atproto.repo.getRecord`*