M
Modular12mo ago
isack

Can anyone help me to solve this error.

GitHub
Mojo/examples/matrix.mojo at main · oderoi/Mojo
Mojo Programming Language. Contribute to oderoi/Mojo development by creating an account on GitHub.
No description
6 Replies
Stole
Stole12mo ago
It looks like a double free, you're calling A.data.free() and etc. for all the matrices after the benchmark is run, but when they get destructed, each __del__ gets called, freeing the pointers again. You can keep the matrices alive a different way, like I just changed those A.data.free() calls to _ = A.rows or quite literally anything that uses the matrices, or remove the free call in __del__. I think the first option is "better" practice for now. This is what I ran, and it appears to work as expected.
from random import rand
from memory import memset, memset_zero
from memory.unsafe import DTypePointer, Pointer
import benchmark

alias type=DType.float64

struct Matrix:
var data: DTypePointer[type]
var rows: Int
var cols: Int

#initisalize zeroing all values
fn __init__(inout self, rows: Int, cols: Int):
self.data = DTypePointer[type].alloc(rows * cols)
memset_zero(self.data, rows*cols)
self.rows = rows
self.cols = cols

#initialize taking a pointer, don't set any elements
fn __init__(inout self, rows: Int, cols: Int , data: DTypePointer[DType.float64]):
self.data=data
self.cols=cols
self.rows=rows

#Initialize with random values

@staticmethod
fn rand(rows: Int, cols: Int)-> Self:
let data = DTypePointer[type].alloc(rows * cols)
rand(data, rows*cols)
return Self(rows, cols, data)

fn __getitem__(self, y: Int, x: Int)->Float64:
return self.load[1](y, x)

fn __setitem__(self, y: Int, x: Int, val: Float64):
return self.store[1](y, x, val)

fn load[nelts: Int](self, y: Int, x: Int) -> SIMD[DType.float64, nelts]:
return self.data.simd_load[nelts](y * self.cols + x)

fn store[nelts: Int](self, y: Int, x: Int, val: SIMD[DType.float64, nelts]):
return self.data.simd_store[nelts](y * self.cols + x, val)

fn __del__(owned self):
self.data.free()


fn print(self):
print_no_newline("[")
for i in range(self.rows*self.cols):
if i > 0:
print_no_newline(", ")
print_no_newline(self.data.load(i))
print("]")

# Note that C, A, and B have types.
fn matmul_naive(C: Matrix, A: Matrix, B: Matrix):
for m in range(C.rows):
for k in range(A.cols):
for n in range(C.cols):
C[m, n] += A[m, k] * B[k, n]



fn main():
alias M = 1024
alias N = 1024
alias K = 1024

@always_inline
fn bench[
func: fn (Matrix, Matrix, Matrix) -> None](base_gflops: Float64):
var C = Matrix(M, N)
var A = Matrix.rand(M, K)
var B = Matrix.rand(K, N)

@always_inline
@parameter
fn test_fn():
_ = func(C, A, B)

let secs = benchmark.run[test_fn](max_runtime_secs=1).mean()
# Prevent the matrices from being freed before the benchmark run
_ = A.rows
_ = B.rows
_ = C.rows
let gflops = ((2 * M * N * K) / secs) / 1e9
#let speedup: Float64 = gflops / base_gflops
print(gflops, "GFLOP/s")
#print(gflops, "GFLOP/s, a", speedup, "x speedup over Python")

bench[matmul_naive](Float64)
from random import rand
from memory import memset, memset_zero
from memory.unsafe import DTypePointer, Pointer
import benchmark

alias type=DType.float64

struct Matrix:
var data: DTypePointer[type]
var rows: Int
var cols: Int

#initisalize zeroing all values
fn __init__(inout self, rows: Int, cols: Int):
self.data = DTypePointer[type].alloc(rows * cols)
memset_zero(self.data, rows*cols)
self.rows = rows
self.cols = cols

#initialize taking a pointer, don't set any elements
fn __init__(inout self, rows: Int, cols: Int , data: DTypePointer[DType.float64]):
self.data=data
self.cols=cols
self.rows=rows

#Initialize with random values

@staticmethod
fn rand(rows: Int, cols: Int)-> Self:
let data = DTypePointer[type].alloc(rows * cols)
rand(data, rows*cols)
return Self(rows, cols, data)

fn __getitem__(self, y: Int, x: Int)->Float64:
return self.load[1](y, x)

fn __setitem__(self, y: Int, x: Int, val: Float64):
return self.store[1](y, x, val)

fn load[nelts: Int](self, y: Int, x: Int) -> SIMD[DType.float64, nelts]:
return self.data.simd_load[nelts](y * self.cols + x)

fn store[nelts: Int](self, y: Int, x: Int, val: SIMD[DType.float64, nelts]):
return self.data.simd_store[nelts](y * self.cols + x, val)

fn __del__(owned self):
self.data.free()


fn print(self):
print_no_newline("[")
for i in range(self.rows*self.cols):
if i > 0:
print_no_newline(", ")
print_no_newline(self.data.load(i))
print("]")

# Note that C, A, and B have types.
fn matmul_naive(C: Matrix, A: Matrix, B: Matrix):
for m in range(C.rows):
for k in range(A.cols):
for n in range(C.cols):
C[m, n] += A[m, k] * B[k, n]



fn main():
alias M = 1024
alias N = 1024
alias K = 1024

@always_inline
fn bench[
func: fn (Matrix, Matrix, Matrix) -> None](base_gflops: Float64):
var C = Matrix(M, N)
var A = Matrix.rand(M, K)
var B = Matrix.rand(K, N)

@always_inline
@parameter
fn test_fn():
_ = func(C, A, B)

let secs = benchmark.run[test_fn](max_runtime_secs=1).mean()
# Prevent the matrices from being freed before the benchmark run
_ = A.rows
_ = B.rows
_ = C.rows
let gflops = ((2 * M * N * K) / secs) / 1e9
#let speedup: Float64 = gflops / base_gflops
print(gflops, "GFLOP/s")
#print(gflops, "GFLOP/s, a", speedup, "x speedup over Python")

bench[matmul_naive](Float64)
isack
isackOP12mo ago
thank you , this helps ,... Also , if i uncomment this : #let speedup: Float64 = gflops / base_gflops #print(gflops, "GFLOP/s, a", speedup, "x speedup over Python") and add : print(gflops, "GFLOP/s", speedup, "speedup") I get that error : can you help me with that as well if you may. Thank you.
No description
Stole
Stole12mo ago
Wow, this is a bad bug. Looks like an actual language one, there's something bad happening under the hood. So far I can't see a way to get around it, would be good to create an issue on the Github https://github.com/modularml/mojo/issues. I took a look and didn't see anything similar to this previously reported.
isack
isackOP12mo ago
ok, thank you so much
Stole
Stole12mo ago
Wait, I completely missed something The reason is because you're passing the type Float64 into bench at the end, when it really expects something of the type Float64, like 1.0 or a variable I guess it's true the compiler should emit a better error than this, but changing that last Float64 to something like 0.5 (I don't know the actual base GFLOPS that Python runs this at) works I think you can go ahead and still make an issue, but make it instead about a better error in this case. Because something like:
fn add(a: Int) -> Int:
return a + 1

fn main():
print(a(Int))
fn add(a: Int) -> Int:
return a + 1

fn main():
print(a(Int))
should probably produce an error less cryptic
isack
isackOP12mo ago
Hi, I have a question ,... using that Matrix struct above, can i perform vectorization in matrix multiplication fn: @always_inline fn mul(self, other: SIMD[type, 1])->Matrix[type]: alias simd_width=simdwidthoftype let result=Matrix[type](self.rows, self.cols) for y in range(self.rows): for x in range(self.cols): result[y, x]=other * self.data.simd_load[1](y * self.cols + x) return result or should i add Tensor in struct : struct[t: Tensor]: is it possible ?
Want results from more Discord servers?
Add your server