```python
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline


_cuda_source = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAGuard.h>
#include <c10/cuda/CUDAStream.h>
#include <c10/cuda/CUDAException.h>
#include <cuda_runtime.h>
#include <algorithm>
#include <cstdint>

__device__ __forceinline__ float4 load_streaming(const float4* p) {
    float4 v;
    asm volatile(
        "ld.global.cs.v4.f32 {%0, %1, %2, %3}, [%4];"
        : "=f"(v.x), "=f"(v.y), "=f"(v.z), "=f"(v.w)
        : "l"(p)
        : "memory");
    return v;
}

__device__ __forceinline__ void store_streaming(
    float4* p, float4 v, float scalar)
{
    v.x *= scalar;
    v.y *= scalar;
    v.z *= scalar;
    v.w *= scalar;
    asm volatile(
        "st.global.cs.v4.f32 [%0], {%1, %2, %3, %4};"
        :
        : "l"(p), "f"(v.x), "f"(v.y), "f"(v.z), "f"(v.w)
        : "memory");
}

template<int THREADS>
__global__ void scalar_mul_streaming(
    const float* __restrict__ input,
    float* __restrict__ output,
    float scalar,
    int64_t count)
{
    const float4* src = reinterpret_cast<const float4*>(input);
    float4* dst = reinterpret_cast<float4*>(output);
    const int64_t vectors = count / 4;
    const int64_t step = static_cast<int64_t>(gridDim.x) * THREADS * 4;
    int64_t i = static_cast<int64_t>(blockIdx.x) * THREADS * 4
                + threadIdx.x;

    for (; i + 3 * THREADS < vectors; i += step) {
        float4 a = load_streaming(src + i);
        float4 b = load_streaming(src + i + THREADS);
        float4 c = load_streaming(src + i + 2 * THREADS);
        float4 d = load_streaming(src + i + 3 * THREADS);

        store_streaming(dst + i, a, scalar);
        store_streaming(dst + i + THREADS, b, scalar);
        store_streaming(dst + i + 2 * THREADS, c, scalar);
        store_streaming(dst + i + 3 * THREADS, d, scalar);
    }

    #pragma unroll
    for (int j = 0; j < 4; ++j) {
        const int64_t k = i + j * THREADS;
        if (k < vectors) {
            store_streaming(dst + k, load_streaming(src + k), scalar);
        }
    }

    if (blockIdx.x == 0 && threadIdx.x < count % 4) {
        const int64_t k = vectors * 4 + threadIdx.x;
        output[k] = input[k] * scalar;
    }
}

__global__ void scalar_mul_unaligned(
    const float* __restrict__ input,
    float* __restrict__ output,
    float scalar,
    int64_t count)
{
    const int64_t step = static_cast<int64_t>(gridDim.x) * blockDim.x;
    for (int64_t i = static_cast<int64_t>(blockIdx.x) * blockDim.x
                     + threadIdx.x;
         i < count; i += step) {
        output[i] = input[i] * scalar;
    }
}

torch::Tensor scalar_mul_cuda(torch::Tensor input, double scalar) {
    TORCH_CHECK(input.is_cuda(), "Expected CUDA input");
    TORCH_CHECK(input.scalar_type() == at::kFloat, "Expected float32 input");
    TORCH_CHECK(input.is_contiguous(), "Expected contiguous input");

    const c10::cuda::CUDAGuard guard(input.device());
    auto output = torch::empty_like(input);
    const int64_t count = input.numel();
    if (count == 0) return output;

    constexpr int threads = 256;
    const int max_blocks =
        at::cuda::getCurrentDeviceProperties()->multiProcessorCount * 8;
    const auto stream =
        c10::cuda::getCurrentCUDAStream(input.get_device()).stream();
    const float* src = input.data_ptr<float>();
    float* dst = output.data_ptr<float>();

    if ((reinterpret_cast<uintptr_t>(src) & 15) == 0) {
        const int blocks = static_cast<int>(std::min<int64_t>(
            (count + threads * 16 - 1) / (threads * 16), max_blocks));
        scalar_mul_streaming<threads><<<blocks, threads, 0, stream>>>(
            src, dst, static_cast<float>(scalar), count);
    } else {
        const int blocks = static_cast<int>(std::min<int64_t>(
            (count + threads - 1) / threads, max_blocks));
        scalar_mul_unaligned<<<blocks, threads, 0, stream>>>(
            src, dst, static_cast<float>(scalar), count);
    }
    C10_CUDA_KERNEL_LAUNCH_CHECK();
    return output;
}
"""

_extension = load_inline(
    name="matrix_scalar_mul_streaming_v2",
    cpp_sources="torch::Tensor scalar_mul_cuda(torch::Tensor input, double scalar);",
    cuda_sources=_cuda_source,
    functions=["scalar_mul_cuda"],
    extra_cflags=["-O3"],
    extra_cuda_cflags=["-O3"],
    verbose=False,
)


class ModelNew(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, A: torch.Tensor, s: float) -> torch.Tensor:
        if (
            A.is_cuda
            and A.dtype == torch.float32
            and A.is_contiguous()
            and not (torch.is_grad_enabled() and A.requires_grad)
        ):
            return _extension.scalar_mul_cuda(A, s)
        return A * s
```